]> granicus.if.org Git - php/commitdiff
Another Fix for Bug #68344 MySQLi does not provide way to disable peer certificate...
authorAndrey Hristov <andrey@php.net>
Tue, 27 Oct 2015 11:59:09 +0000 (12:59 +0100)
committerAndrey Hristov <andrey@php.net>
Tue, 27 Oct 2015 11:59:09 +0000 (12:59 +0100)
Added the possibility to explicitly state that the peer certificate should not be checked.
Back to the default - checking the certificate.
Exported MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT
Usage : mysqli_real_connect( , , , , , MYSQLI_CLIENT_SSL | MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT)

If mysqli_ssl_set() is not called, but only MYSQLI_CLIENT_SSL is passed, without the (don't) very flag,
then no verification takes place.

ext/mysqli/mysqli.c
ext/mysqli/tests/bug51647.phpt
ext/mysqli/tests/bug55283.phpt
ext/mysqli/tests/connect.inc
ext/mysqli/tests/mysqli_constants.phpt
ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd_enum_n_def.h
ext/mysqlnd/mysqlnd_net.c
ext/mysqlnd/mysqlnd_structs.h

index 198ed8311660bc76db01e1012cfa617641cedd66..5e40d1913017ed5349d1ce6e2c40e2072b05bd09 100644 (file)
@@ -717,6 +717,9 @@ PHP_MINIT_FUNCTION(mysqli)
        REGISTER_LONG_CONSTANT("MYSQLI_CLIENT_FOUND_ROWS", CLIENT_FOUND_ROWS, CONST_CS | CONST_PERSISTENT);
 #ifdef CLIENT_SSL_VERIFY_SERVER_CERT
        REGISTER_LONG_CONSTANT("MYSQLI_CLIENT_SSL_VERIFY_SERVER_CERT", CLIENT_SSL_VERIFY_SERVER_CERT, CONST_CS | CONST_PERSISTENT);
+#if defined(MYSQLI_USE_MYSQLND)
+       REGISTER_LONG_CONSTANT("MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT", CLIENT_SSL_DONT_VERIFY_SERVER_CERT, CONST_CS | CONST_PERSISTENT);
+#endif
 #endif
 #if (MYSQL_VERSION_ID >= 50611 && defined(CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS)) || defined(MYSQLI_USE_MYSQLND)
        REGISTER_LONG_CONSTANT("MYSQLI_CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS", CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS, CONST_CS | CONST_PERSISTENT);
index 349d6dbbb0101c47e422638bd6cae1ffae814b3d..7385538fbbb3f085bccbf3e813687de22ffb3955 100644 (file)
@@ -41,11 +41,7 @@ $link->close();
        if (!is_object($link = mysqli_init()))
                printf("[001] Cannot create link\n");
 
-       $path_to_pems = !$IS_MYSQLND? "ext/mysqli/tests/" : "";
-       if (!$link->ssl_set("{$path_to_pems}client-key.pem", "{$path_to_pems}client-cert.pem", "{$path_to_pems}cacert.pem","",""))
-               printf("[002] [%d] %s\n", $link->errno, $link->error);
-
-       if (!my_mysqli_real_connect($link, $host, $user, $passwd, $db, $port, $socket)) {
+       if (!my_mysqli_real_connect($link, $host, $user, $passwd, $db, $port, $socket, MYSQLI_CLIENT_SSL | MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT)) {
                printf("[003] Connect failed, [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
        }
 
@@ -67,9 +63,9 @@ $link->close();
                        printf("[006] [%d] %s\n", $link->errno, $link->error);
                if (!strlen($row["Value"]))
                        printf("[007] Empty cipher. No encrytion!");
+               var_dump($row);
        }
 
-       var_dump($row);
        $link->close();
 
        if (!is_object($link = mysqli_init()))
@@ -97,10 +93,9 @@ $link->close();
                        printf("[012] [%d] %s\n", $link->errno, $link->error);
                if (!strlen($row["Value"]))
                        printf("[013] Empty cipher. No encrytion!");
+               var_dump($row);
        }
 
-       var_dump($row);
-
        $link->close();
 
        print "done!";
index d03daaee88e75f953525423598ff4b2615aa0e3d..a10c604fdd61f285ac527ce7668aab5c435942e7 100644 (file)
@@ -40,7 +40,7 @@ $link->close();
        $db1 = new mysqli();
 
 
-       $flags = MYSQLI_CLIENT_SSL;
+       $flags = MYSQLI_CLIENT_SSL | MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT;
 
        $link = mysqli_init();
        mysqli_ssl_set($link, null, null, null, null, "RC4-MD5");
index 67ce60a48bd6b0697f8a5c888013bcf70d9734d8..606d1d32eb5298dd7f12e882116b3ac1d72cdd83 100644 (file)
@@ -9,7 +9,7 @@
        $driver    = new mysqli_driver;
 
        $host      = getenv("MYSQL_TEST_HOST")     ? getenv("MYSQL_TEST_HOST") : "127.0.0.1";
-       $port      = getenv("MYSQL_TEST_PORT")     ? getenv("MYSQL_TEST_PORT") : 3308;
+       $port      = getenv("MYSQL_TEST_PORT")     ? getenv("MYSQL_TEST_PORT") : 3306;
        $user      = getenv("MYSQL_TEST_USER")     ? getenv("MYSQL_TEST_USER") : "root";
        $passwd    = getenv("MYSQL_TEST_PASSWD")   ? getenv("MYSQL_TEST_PASSWD") : "";
        $db        = getenv("MYSQL_TEST_DB")       ? getenv("MYSQL_TEST_DB") : "test";
@@ -87,9 +87,8 @@
                function my_mysqli_connect($host, $user, $passwd, $db, $port, $socket, $enable_env_flags = true) {
                        global $connect_flags;
 
-                       $flags = ($enable_env_flags) ? $connect_flags : false;
-
-                       if ($flags !== false) {
+                       $flags = $enable_env_flags? $connect_flags:0;
+                       if ($flags !== 0) {
                                $link = mysqli_init();
                                if (!mysqli_real_connect($link, $host, $user, $passwd, $db, $port, $socket, $flags))
                                        $link = false;
                        global $connect_flags;
 
                        if ($enable_env_flags)
-                               $flags & $connect_flags;
+                               $flags = $flags | $connect_flags;
 
                        return mysqli_real_connect($link, $host, $user, $passwd, $db, $port, $socket, $flags);
                }
                        public function __construct($host, $user, $passwd, $db, $port, $socket, $enable_env_flags = true) {
                                global $connect_flags;
 
-                               $flags = ($enable_env_flags) ? $connect_flags : false;
+                               $flags = ($enable_env_flags) ? $connect_flags : 0;
 
                                if ($flags !== false) {
                                        parent::init();
index 1cb31cc2a72aef891ea49d4688fbeafc49e43afe..cc5fa9f1c4261f87d8262a00ed441f841919c35d 100644 (file)
@@ -139,6 +139,9 @@ require_once('skipifconnectfailure.inc');
        if ($version >= 50033 || $IS_MYSQLND) {
                $expected_constants['MYSQLI_CLIENT_SSL_VERIFY_SERVER_CERT'] = true;
        }
+       if ($IS_MYSQLND) {
+               $expected_constants['MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT'] = true;
+       }
 
        /* First introduced in MySQL 6.0, backported to MySQL 5.5 */
        if ($version >= 50606 || $IS_MYSQLND) {
index f0089862273a683290a510f2cd8a61ad1ffbb3fe..94a314964d0c401ef7551ad6d2bf5caadcb1375e 100644 (file)
@@ -472,6 +472,7 @@ mysqlnd_switch_to_ssl_if_needed(
        DBG_INF_FMT("CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA=     %d", mysql_flags & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA? 1:0);
        DBG_INF_FMT("CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS=       %d", mysql_flags & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS? 1:0);
        DBG_INF_FMT("CLIENT_SESSION_TRACK=              %d", mysql_flags & CLIENT_SESSION_TRACK? 1:0);
+       DBG_INF_FMT("CLIENT_SSL_DONT_VERIFY_SERVER_CERT=        %d", mysql_flags & CLIENT_SSL_DONT_VERIFY_SERVER_CERT? 1:0);
        DBG_INF_FMT("CLIENT_SSL_VERIFY_SERVER_CERT=     %d", mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? 1:0);
        DBG_INF_FMT("CLIENT_REMEMBER_OPTIONS=           %d", mysql_flags & CLIENT_REMEMBER_OPTIONS? 1:0);
 
@@ -495,7 +496,11 @@ mysqlnd_switch_to_ssl_if_needed(
                if (server_has_ssl == FALSE) {
                        goto close_conn;
                } else {
-                       zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE;
+                       enum mysqlnd_ssl_peer verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT?
+                                                                                               MYSQLND_SSL_PEER_VERIFY:
+                                                                                               (mysql_flags & CLIENT_SSL_DONT_VERIFY_SERVER_CERT?
+                                                                                                       MYSQLND_SSL_PEER_DONT_VERIFY:
+                                                                                                       MYSQLND_SSL_PEER_DEFAULT);
                        DBG_INF("Switching to SSL");
                        if (!PACKET_WRITE(auth_packet, conn)) {
                                goto close_conn;
index c1ede7e65629f56df2304319c8187473889366ea..9e29da29ddd02b549eabbadd9bf7d29720b55a6b 100644 (file)
 #define CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA  (1UL << 21) /* Enable authentication response packet to be larger than 255 bytes. */
 #define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS            (1UL << 22) /* Don't close the connection for a connection with expired password. */
 #define CLIENT_SESSION_TRACK                                   (1UL << 23) /* Extended OK */
+/*
+  This is a mysqlnd extension. CLIENT_ODBC is not used anyway. We will reuse it for our case and translate it to not using SSL peer verification
+*/
+#define CLIENT_SSL_DONT_VERIFY_SERVER_CERT     CLIENT_ODBC
 #define CLIENT_SSL_VERIFY_SERVER_CERT  (1UL << 30)
 #define CLIENT_REMEMBER_OPTIONS                        (1UL << 31)
 
index 7b164ac29424b06f46807cb5655f0cb8ea5a596c..3e8d0993fa12ee52f31b1e93a48bb41879ae2db1 100644 (file)
@@ -798,8 +798,27 @@ MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum mys
                                break;
                        }
                case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
-                       net->data->options.ssl_verify_peer = value? ((*(zend_bool *)value)? TRUE:FALSE): FALSE;
+               {
+                       enum mysqlnd_ssl_peer val = *((enum mysqlnd_ssl_peer *)value);
+                       switch (val) {
+                               case MYSQLND_SSL_PEER_VERIFY:
+                                       DBG_INF("MYSQLND_SSL_PEER_VERIFY");
+                                       break;
+                               case MYSQLND_SSL_PEER_DONT_VERIFY:
+                                       DBG_INF("MYSQLND_SSL_PEER_DONT_VERIFY");
+                                       break;
+                               case MYSQLND_SSL_PEER_DEFAULT:
+                                       DBG_INF("MYSQLND_SSL_PEER_DEFAULT");
+                                       val = MYSQLND_SSL_PEER_DEFAULT;
+                                       break;
+                               default:
+                                       DBG_INF("default = MYSQLND_SSL_PEER_DEFAULT_ACTION");
+                                       val = MYSQLND_SSL_PEER_DEFAULT;
+                                       break;
+                       }
+                       net->data->options.ssl_verify_peer = val;
                        break;
+               }
                case MYSQL_OPT_READ_TIMEOUT:
                        net->data->options.timeout_read = *(unsigned int*) value;
                        break;
@@ -886,6 +905,7 @@ 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 * net_stream = net->data->m.get_stream(net TSRMLS_CC);
+       zend_bool any_flag = FALSE;
 
        DBG_ENTER("mysqlnd_net::enable_ssl");
        if (!context) {
@@ -896,12 +916,7 @@ MYSQLND_METHOD(mysqlnd_net, enable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
                zval key_zval;
                ZVAL_STRING(&key_zval, net->data->options.ssl_key, 0);
                php_stream_context_set_option(context, "ssl", "local_pk", &key_zval);
-       }
-       {
-               zval verify_peer_zval;
-               ZVAL_BOOL(&verify_peer_zval, net->data->options.ssl_verify_peer);
-               php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
-               php_stream_context_set_option(context, "ssl", "verify_peer_name", &verify_peer_zval);
+               any_flag = TRUE;
        }
        if (net->data->options.ssl_cert) {
                zval cert_zval;
@@ -910,27 +925,48 @@ MYSQLND_METHOD(mysqlnd_net, enable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
                if (!net->data->options.ssl_key) {
                        php_stream_context_set_option(context, "ssl", "local_pk", &cert_zval);
                }
+               any_flag = TRUE;
        }
        if (net->data->options.ssl_ca) {
                zval cafile_zval;
                ZVAL_STRING(&cafile_zval, net->data->options.ssl_ca, 0);
                php_stream_context_set_option(context, "ssl", "cafile", &cafile_zval);
+               any_flag = TRUE;
        }
        if (net->data->options.ssl_capath) {
                zval capath_zval;
                ZVAL_STRING(&capath_zval, net->data->options.ssl_capath, 0);
                php_stream_context_set_option(context, "ssl", "capath", &capath_zval);
+               any_flag = TRUE;
        }
        if (net->data->options.ssl_passphrase) {
                zval passphrase_zval;
                ZVAL_STRING(&passphrase_zval, net->data->options.ssl_passphrase, 0);
                php_stream_context_set_option(context, "ssl", "passphrase", &passphrase_zval);
+               any_flag = TRUE;
        }
        if (net->data->options.ssl_cipher) {
                zval cipher_zval;
                ZVAL_STRING(&cipher_zval, net->data->options.ssl_cipher, 0);
                php_stream_context_set_option(context, "ssl", "ciphers", &cipher_zval);
+               any_flag = TRUE;
+       }
+       {
+               zval verify_peer_zval;
+               zend_bool verify;
+
+               if (net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_DEFAULT) {
+                       net->data->options.ssl_verify_peer = any_flag? MYSQLND_SSL_PEER_DEFAULT_ACTION:MYSQLND_SSL_PEER_DONT_VERIFY;
+               }
+
+               verify = net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_VERIFY? TRUE:FALSE;
+
+               DBG_INF_FMT("VERIFY=%d", verify);
+               ZVAL_BOOL(&verify_peer_zval, verify);
+               php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
+               php_stream_context_set_option(context, "ssl", "verify_peer_name", &verify_peer_zval);
        }
+
        php_stream_context_set(net_stream, context);
        if (php_stream_xport_crypto_setup(net_stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL TSRMLS_CC) < 0 ||
            php_stream_xport_crypto_enable(net_stream, 1 TSRMLS_CC) < 0)
index 170c977c2b821e1aec6669035ea89fbf027f2043..f5d0b47a6f0ba96974a3a0f5d9b2103300b56b87 100644 (file)
@@ -207,7 +207,13 @@ typedef struct st_mysqlnd_net_options
        char            *ssl_capath;
        char            *ssl_cipher;
        char            *ssl_passphrase;
-       zend_bool       ssl_verify_peer;
+       enum mysqlnd_ssl_peer {
+               MYSQLND_SSL_PEER_DEFAULT = 0,
+               MYSQLND_SSL_PEER_VERIFY = 1,
+               MYSQLND_SSL_PEER_DONT_VERIFY = 2,
+
+#define MYSQLND_SSL_PEER_DEFAULT_ACTION  MYSQLND_SSL_PEER_VERIFY
+       } ssl_verify_peer;
        uint64_t        flags;
 
        char *          sha256_server_public_key;
@@ -219,6 +225,7 @@ typedef struct st_mysqlnd_net_options
 } MYSQLND_NET_OPTIONS;
 
 
+
 typedef struct st_mysqlnd_connection MYSQLND;
 typedef struct st_mysqlnd_connection_data MYSQLND_CONN_DATA;
 typedef struct st_mysqlnd_net  MYSQLND_NET;