php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #71003 Expose MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT to PDO interface
Submitted: 2015-11-30 23:43 UTC Modified: 2016-05-18 17:52 UTC
Votes:30
Avg. Score:4.8 ± 0.6
Reproduced:28 of 28 (100.0%)
Same Version:15 (53.6%)
Same OS:10 (35.7%)
From: tmatsuo at google dot com Assigned: andrey
Status: Closed Package: PDO MySQL
PHP Version: 5.6.16 OS:
Private report: No CVE-ID:
 [2015-11-30 23:43 UTC] tmatsuo at google dot com
Description:
------------
According to the bug #68344, with PHP 5.6.16, you can ignore the peer name verification upon establishing the connection. This is great, however according to https://secure.php.net/manual/en/ref.pdo-mysql.php, this option is not exposed to PDO interface.

Please provide a way to specify MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT when using the PDO interface.

Expected result:
----------------
You can somehow instruct PDO that it ignores the peer name of the certificate upon establish an SSL connection.


Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-03-14 10:25 UTC] php at yblew dot com
Any update on this?
 [2016-04-04 09:23 UTC] nj dot johansson at gmail dot com
A nice solution would be to be able to explicitly pass a peer name that should be expected using http://php.net/manual/en/context.ssl.php#context.ssl.verify-peer-name

My use case is that we have a CNAME record pointing at an AWS RDS instance (*.rds.amazonaws.com) to be able to easily switch the underlying instance. However, lacking other information PHP will since 5.6 try to guess the peer name using the hostname provided and peer name verification will as such fail.

I also understand that for some use cases (see http://stackoverflow.com/questions/29260464/google-cloud-sql-ssl-fails-peer-certificate-validation) it is out of the developer's control what the Common Name (CN) for the remote database will be assigned to, however, given the same option as suggested above it would still be possible to connect.
 [2016-04-13 15:13 UTC] phpbugs at bazoink dot com
I'm still working on getting PDO to support CLIENT_SSL_DONT_VERIFY_SERVER_CERT, in the meantime, if you want to change the default for PDO (and it's set to use mysqlnd, which it probably is, change this line and recompile:

php-5.6.20/ext/mysqlnd/mysqlnd_structs.h line 215 
change 
#define MYSQLND_SSL_PEER_DEFAULT_ACTION  MYSQLND_SSL_PEER_VERIFY
to
#define MYSQLND_SSL_PEER_DEFAULT_ACTION MYSQLND_SSL_PEER_DONT_VERIFY

That will give you the pre-5.6 behavior of not verifying the CN.

I hope to have a working patch to add the option to PDO this weekend. I'm close, but not complete.

Mark
 [2016-05-15 20:28 UTC] zhil dot mobile at gmail dot com
Any news regarding this bug?
 [2016-05-18 02:05 UTC] requinix@php.net
See also bug #71845 about the general CN mismatch problem.
 [2016-05-18 16:55 UTC] highmind63 at gmail dot com
For all those trying to get this to work, don't. There is no possible way to make this work, in all of my tests. You MUST have a valid commercial certificate and it MUST match the name of the host. I've tried the following to no avail:

set PDO::MYSQL_ATTR_SSL_CAPATH option to a properly hashed dir (one that I tested and works with CURLOPT_CAPATH). No go

set openssl.capath to the same properly hashed dir. No go, completely ignored.

I tried fiddling around a bit with openssl's internal cert store, but I couldn't get that to work. That should work, but at the expense of changing all the openssl cert store data system-wide.

This is a big defect in PHP's PDO currently, PDO over SSL is barely useable as-is.
 [2016-05-18 17:52 UTC] nikic@php.net
-Assigned To: +Assigned To: andrey
 [2016-05-18 17:52 UTC] nikic@php.net
@andrey: You implemented the mysqli fix for this issue, could you maybe take a look at PDO mysql as well?
 [2016-05-22 17:58 UTC] zhil dot mobile at gmail dot com
I have setuped free SSL sertificate from http://buy.wosign.com/free/
It works on SSH console using mysql command like

mysql -h myhost.com --ssl --ssl-ca=/.../wosign/root_bundle.crt --ssl-verify-server-cert --ssl-mode=REQUIRED DBNAME -u USERNAME -pPASS

But I failed to make it work using php PDO mysql.
I am considering creating SSH tunel for remote mysql instead of spending more time on this issue.

Do anybody have any ideas how could it be fixed?
 [2016-06-09 10:38 UTC] thomas at orozco dot fr
Hi there,

The following patch seems to work for me with some limited testing (it just sets CLIENT_SSL_VERIFY_SERVER_CERT and the heavy lifting is done by the code from https://bugs.php.net/bug.php?id=68344).

Is this worth submitting as a PR https://github.com/php/php-src? Is there anything I can do to help move this forward?

---

From ff2c31450a7f5ca2c32b49873c5d6e1a0de67674 Mon Sep 17 00:00:00 2001
From: Thomas Orozco <thomas@orozco.fr>
Date: Thu, 9 Jun 2016 10:45:40 +0200
Subject: [PATCH] Add PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT

---
 ext/pdo_mysql/mysql_driver.c                       | 12 ++++++++++++
 ext/pdo_mysql/pdo_mysql.c                          |  3 +++
 ext/pdo_mysql/php_pdo_mysql_int.h                  |  3 +++
 ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt |  1 +
 4 files changed, 19 insertions(+)

diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
index 1b1d1ab..20ae458 100644
--- a/ext/pdo_mysql/mysql_driver.c
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -731,6 +731,18 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
 			}
 		}
 #endif
+
+#ifdef PDO_USE_MYSQLND
+		{
+			zend_long ssl_verify_cert = pdo_attr_lval(driver_options,
+					PDO_MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, -1);
+			if (ssl_verify_cert != -1) {
+				connect_opts |= ssl_verify_cert ?
+					CLIENT_SSL_VERIFY_SERVER_CERT:
+					CLIENT_SSL_DONT_VERIFY_SERVER_CERT;
+			}
+		}
+#endif
 	}
 
 #ifdef PDO_MYSQL_HAS_CHARSET
diff --git a/ext/pdo_mysql/pdo_mysql.c b/ext/pdo_mysql/pdo_mysql.c
index fdf7062..79efb21 100644
--- a/ext/pdo_mysql/pdo_mysql.c
+++ b/ext/pdo_mysql/pdo_mysql.c
@@ -130,6 +130,9 @@ static PHP_MINIT_FUNCTION(pdo_mysql)
 	 REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SERVER_PUBLIC_KEY", (zend_long)PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY);
 #endif
 	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_MULTI_STATEMENTS", (zend_long)PDO_MYSQL_ATTR_MULTI_STATEMENTS);
+#ifdef PDO_USE_MYSQLND
+	 REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_VERIFY_SERVER_CERT", (zend_long)PDO_MYSQL_ATTR_SSL_VERIFY_SERVER_CERT);
+#endif
 
 #ifdef PDO_USE_MYSQLND
 	mysqlnd_reverse_api_register_api(&pdo_mysql_reverse_api);
diff --git a/ext/pdo_mysql/php_pdo_mysql_int.h b/ext/pdo_mysql/php_pdo_mysql_int.h
index 20d640c..08eb731 100644
--- a/ext/pdo_mysql/php_pdo_mysql_int.h
+++ b/ext/pdo_mysql/php_pdo_mysql_int.h
@@ -179,6 +179,9 @@ enum {
 	PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY,
 #endif
 	PDO_MYSQL_ATTR_MULTI_STATEMENTS,
+#ifdef PDO_USE_MYSQLND
+	PDO_MYSQL_ATTR_SSL_VERIFY_SERVER_CERT,
+#endif
 };
 
 #endif
diff --git a/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt b/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
index f3d0fa6..fba1c24 100644
--- a/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
+++ b/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
@@ -27,6 +27,7 @@ if (!extension_loaded('mysqli') && !extension_loaded('mysqlnd')) {
 		"MYSQL_ATTR_SSL_CIPHER"						=> true,
 		"MYSQL_ATTR_COMPRESS"						=> true,
 		"MYSQL_ATTR_MULTI_STATEMENTS"					=> true,
+		"MYSQL_ATTR_SSL_VERIFY_SERVER_CERT"				=> true,
 	);
 
 	if (!MySQLPDOTest::isPDOMySQLnd()) {
-- 
2.7.4
 [2016-06-09 11:13 UTC] thomas at orozco dot fr
(I should mention that the above patch is for the master branch of php-src, but adjusting the `zend_long`s to be `long`s instead makes it work just fine on PHP 5.6.22)
 [2016-06-21 15:17 UTC] mrpatricktully at gmail dot com
We just ran into this same issue.  Seeing as re-compiling php with this patch is not really an option for us (config management setup), we did try the following work around and can confirm it works.  Assuming the CN is something like a hostname (i.e. project name or something other an an IP address).  You can hardcode the name in the local hosts file of the client servers.  i.e. if the CN=server and the mysql server is 192.168.2.1 putting this in your hosts file, then setting the host to "server" in php works

192.168.2.1  server

This only works of course if you have a one to one match (i.e. won't work if you have more than one server using the same cert).  Not really an ideal solution but it does work if you are in a bind.  Hopefully the patch will be rolled into a release?
 [2016-12-03 01:57 UTC] jeremy at boldapps dot net
I added a PR for this bug a few months ago. https://github.com/php/php-src/pull/1972 Anything else I need to do to get it considered?
 [2017-03-09 16:32 UTC] nikic@php.net
Automatic comment on behalf of thomas@orozco.fr
Revision: http://git.php.net/?p=php-src.git;a=commit;h=247ce052cd0fc7d0d8ea1a0e7ea2075e9601766a
Log: Fixed bug #71003: Add PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT
 [2017-03-09 16:32 UTC] nikic@php.net
-Status: Assigned +Status: Closed
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue Aug 29 15:01:52 2017 UTC