summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Hristov <andrey@php.net>2015-10-27 12:59:09 +0100
committerAndrey Hristov <andrey@php.net>2015-10-27 12:59:09 +0100
commit6d51b7b2e3468601acdaaf9041c9131b5aa47f98 (patch)
tree2f2c193dc999941727f61c118ef06f532ff3e7e9
parent2f7a8515ca7f3ab4b0640677e4f476f87642ff61 (diff)
downloadphp-git-6d51b7b2e3468601acdaaf9041c9131b5aa47f98.tar.gz
Another Fix for Bug #68344 MySQLi does not provide way to disable peer certificate validation
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.
-rw-r--r--ext/mysqli/mysqli.c3
-rw-r--r--ext/mysqli/tests/bug51647.phpt11
-rw-r--r--ext/mysqli/tests/bug55283.phpt2
-rw-r--r--ext/mysqli/tests/connect.inc11
-rw-r--r--ext/mysqli/tests/mysqli_constants.phpt3
-rw-r--r--ext/mysqlnd/mysqlnd.c7
-rw-r--r--ext/mysqlnd/mysqlnd_enum_n_def.h4
-rw-r--r--ext/mysqlnd/mysqlnd_net.c50
-rw-r--r--ext/mysqlnd/mysqlnd_structs.h9
9 files changed, 76 insertions, 24 deletions
diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c
index 198ed83116..5e40d19130 100644
--- a/ext/mysqli/mysqli.c
+++ b/ext/mysqli/mysqli.c
@@ -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);
diff --git a/ext/mysqli/tests/bug51647.phpt b/ext/mysqli/tests/bug51647.phpt
index 349d6dbbb0..7385538fbb 100644
--- a/ext/mysqli/tests/bug51647.phpt
+++ b/ext/mysqli/tests/bug51647.phpt
@@ -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!";
diff --git a/ext/mysqli/tests/bug55283.phpt b/ext/mysqli/tests/bug55283.phpt
index d03daaee88..a10c604fdd 100644
--- a/ext/mysqli/tests/bug55283.phpt
+++ b/ext/mysqli/tests/bug55283.phpt
@@ -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");
diff --git a/ext/mysqli/tests/connect.inc b/ext/mysqli/tests/connect.inc
index 67ce60a48b..606d1d32eb 100644
--- a/ext/mysqli/tests/connect.inc
+++ b/ext/mysqli/tests/connect.inc
@@ -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;
@@ -109,7 +108,7 @@
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);
}
@@ -118,7 +117,7 @@
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();
diff --git a/ext/mysqli/tests/mysqli_constants.phpt b/ext/mysqli/tests/mysqli_constants.phpt
index 1cb31cc2a7..cc5fa9f1c4 100644
--- a/ext/mysqli/tests/mysqli_constants.phpt
+++ b/ext/mysqli/tests/mysqli_constants.phpt
@@ -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) {
diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c
index f008986227..94a314964d 100644
--- a/ext/mysqlnd/mysqlnd.c
+++ b/ext/mysqlnd/mysqlnd.c
@@ -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;
diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h
index c1ede7e656..9e29da29dd 100644
--- a/ext/mysqlnd/mysqlnd_enum_n_def.h
+++ b/ext/mysqlnd/mysqlnd_enum_n_def.h
@@ -101,6 +101,10 @@
#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)
diff --git a/ext/mysqlnd/mysqlnd_net.c b/ext/mysqlnd/mysqlnd_net.c
index 7b164ac294..3e8d0993fa 100644
--- a/ext/mysqlnd/mysqlnd_net.c
+++ b/ext/mysqlnd/mysqlnd_net.c
@@ -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)
diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h
index 170c977c2b..f5d0b47a6f 100644
--- a/ext/mysqlnd/mysqlnd_structs.h
+++ b/ext/mysqlnd/mysqlnd_structs.h
@@ -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;