Bug #68344 [Com]: MySQLi does not provide way to disable peer certificate validation

From: Date: Mon, 10 Aug 2015 10:23:18 +0000
Subject: Bug #68344 [Com]: MySQLi does not provide way to disable peer certificate validation
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-195078@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=68344&edit=1

 ID:                 68344
 Comment by:         arekm at maven dot pl
 Reported by:        james at jamesreno dot com
 Summary:            MySQLi does not provide way to disable peer
                     certificate validation
 Status:             No Feedback
 Type:               Bug
 Package:            MySQLi related
 Operating System:   NA
 PHP Version:        5.6.2
 Assigned To:        mysql
 Block user comment: N
 Private report:     N

 New Comment:

More, mysqli internally uses mysqlnd, which creates new context in mysqlnd_net::enable_ssl thus
ignoring default context.

Whit patch below I'm getting default context being used.

diff --git a/ext/mysqlnd/mysqlnd_net.c b/ext/mysqlnd/mysqlnd_net.c
index 8683248..2f63961 100644
--- a/ext/mysqlnd/mysqlnd_net.c
+++ b/ext/mysqlnd/mysqlnd_net.c
@@ -29,6 +29,7 @@
 #include "mysqlnd_ext_plugin.h"
 #include "php_network.h"
 #include "zend_ini.h"
+#include "ext/standard/file.h"
 #ifdef MYSQLND_COMPRESSION_ENABLED
 #include <zlib.h>
 #endif
@@ -859,7 +860,7 @@ static enum_func_status
 MYSQLND_METHOD(mysqlnd_net, enable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
 {
 #ifdef MYSQLND_SSL_SUPPORTED
-       php_stream_context * context = php_stream_context_alloc(TSRMLS_C);
+       php_stream_context * context = FG(default_context) ? FG(default_context) :
php_stream_context_alloc(TSRMLS_C);
        php_stream * net_stream = net->data->m.get_stream(net TSRMLS_CC);

        DBG_ENTER("mysqlnd_net::enable_ssl");


Unfortunately above method means that mysqlnd will change some settings
in default context. What we need to do is to leave creation of new context
but then copy all options from default context to our new context, pseudocode:

php_stream_context * context = php_stream_context_alloc(TSRMLS_C);

copy_all_options_from_default_context_to_new_context(context, default_context)


Don't see any internal function that could do that, so someone with code knowledge would have
to write it.


Previous Comments:
------------------------------------------------------------------------
[2015-08-10 09:12:48] arekm at maven dot pl

"nicely sets GET_VER_OPT("verify_peer") and
GET_VER_OPT("verify_peer_name")) to 0, which is fine."

or rather these are 0 by default.... so default context options are actually not being passed here
:-/

------------------------------------------------------------------------
[2015-08-10 07:51:01] arekm at maven dot pl

Ok, the problem comes from generic openssl code:

ext/openssl/xp_ssl.c, apply_peer_verification_policy() function

    must_verify_peer = GET_VER_OPT("verify_peer")
        ? zend_is_true(*val)
        : sslsock->is_client;

    has_cnmatch_ctx_opt = GET_VER_OPT("CN_match");
    must_verify_peer_name = (has_cnmatch_ctx_opt || GET_VER_OPT("verify_peer_name"))
        ? zend_is_true(*val)
        : sslsock->is_client;


Now code:

$opts = array('ssl'=>array('verify_peer'=> false,
'verify_peer_name' => false));
stream_context_set_default($opts);

nicely sets GET_VER_OPT("verify_peer") and GET_VER_OPT("verify_peer_name")) to
0, which is fine.

Unfortunately above code fallback to sslsock->is_client which is 1. That means that if we are
client (is_client==1) then openssl extension ignores our verify_peer and verify_peer_name settings.
Why is that? No idea.


If I'm looking correctly then this commit changed behaviour:

commit ce8dc0ede2e8084beef1e7b03c8960e938c8399f
Author: Daniel Lowrey <rdlowrey@php.net>
Date:   Fri Feb 14 15:17:30 2014 -0700

    Bug #47030 (separate host and peer verification)

Previously it behaved differently for is_client == 1.

------------------------------------------------------------------------
[2015-08-09 20:03:26] arekm at maven dot pl

"Warning: mysqli_real_connect(): Peer certificate CN=.... did not match expected CN" comes
from openssl/xp_ssl.c

That code uses php stream functions like:

 stream = php_stream_alloc_rel(&php_openssl_socket_ops, sslsock, persistent_id, "r+");

...

then php_openssl_socket_ops structure has php_openssl_sockop_set_option function which then call few
functions and is some cases raises above error.

apply_peer_verification_policy actually checks verify_peer:

   must_verify_peer = GET_VER_OPT("verify_peer")
        ? zend_is_true(*val)
        : sslsock->is_client;


so it should be possible to switch this check off. Unfortunately for me php 5.6.12 is ignoring
setting for this:

$opts = array('ssl'=>array('verify_peer'=> false,
'verify_peer_name' => false));
stream_context_set_default($opts);

$cb = mysqli_init();
mysqli_ssl_set($cb, null, null, null, null, null);
mysqli_real_connect($cb,$db_host, $db_user, $db_pass, $db_name, false, false, MYSQLI_CLIENT_SSL)

and yet I'm getting
"Warning: mysqli_real_connect(): Peer certificate CN=.... did not match expected CN"


So the question is - why openssl code ignores verify_peer setting from default context?

------------------------------------------------------------------------
[2015-08-07 12:08:28] t dot launer at intershop dot de

I've been watching this bug entry for some time now and actually thought this issue was too
important not to be fixed fast. A number of our systems are affected by this bug, seeing that we
maintain a set of distributed applications and a central MySQL server that hosts all the
company's MySQL database instances with which every application server (OTRS, Wikis, ...) must
communicate via X509. I simply cannot upgrade their PHP to 5.6 because that required abandoning our
security policy.
I agree with "spam2 at rhsoft dot net" in that it is a security measure to create server
and client certificates from a CA that is hidden to everyone.

Please consider fixing this bug in 5.6 soon - or at least make the 5.5 functionality available as
option again in version 7.

------------------------------------------------------------------------
[2015-08-07 07:31:24] spam2 at rhsoft dot net

and another month is gone where peole which using encryption for anything which make sit to a
ethernet cable the last years CAN NOT UPGRADE TO PHP 5.6 - holy crap mysql encryption in general
broke repeatly without even push a fixing update in a tiemly manner, now it's broken again -
that's all a joke

------------------------------------------------------------------------


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    https://bugs.php.net/bug.php?id=68344


--
Edit this bug report at https://bugs.php.net/bug.php?id=68344&edit=1


Thread (57 messages)

« previous php.bugs (#195078) next »