summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xext/openssl/openssl.c135
-rw-r--r--ext/openssl/tests/bug65538.pharbin0 -> 9402 bytes
-rw-r--r--ext/openssl/tests/bug65538_001.phpt51
-rw-r--r--ext/openssl/tests/bug65538_002.phpt22
-rw-r--r--ext/openssl/tests/bug65538_003.phpt52
5 files changed, 234 insertions, 26 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 1dc93e5078..04d8b5ea23 100755
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -699,7 +699,7 @@ static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
return (time_t)-1;
}
- if (ASN1_STRING_length(timestr) != strlen(ASN1_STRING_data(timestr))) {
+ if (ASN1_STRING_length(timestr) != strlen((const char*)ASN1_STRING_data(timestr))) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal length in timestamp");
return (time_t)-1;
}
@@ -5046,10 +5046,10 @@ static zend_bool matches_san_list(X509 *peer, const char *subject_name TSRMLS_DC
ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName);
/* prevent null byte poisoning */
- if (san_name_len != strlen(cert_name)) {
+ if (san_name_len != strlen((const char*)cert_name)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer SAN entry is malformed");
} else {
- is_match = strcasecmp(subject_name, cert_name) == 0;
+ is_match = strcasecmp(subject_name, (const char*)cert_name) == 0;
}
OPENSSL_free(cert_name);
@@ -5194,6 +5194,110 @@ static int passwd_callback(char *buf, int num, int verify, void *data) /* {{{ */
}
/* }}} */
+static long load_stream_cafile(X509_STORE *cert_store, const char *cafile TSRMLS_DC) /* {{{ */
+{
+ php_stream *stream;
+ X509 *cert;
+ BIO *buffer;
+ int buffer_active;
+ char *line;
+ size_t line_len;
+ long certs_added = 0;
+ const char *begin_line = "-----BEGIN CERTIFICATE-----\n";
+ const char *end_line = "-----END CERTIFICATE-----\n";
+
+ stream = php_stream_open_wrapper(cafile, "rb", 0, NULL);
+
+ if (stream == NULL) {
+ php_error(E_WARNING, "failed loading cafile stream: `%s'", cafile);
+ return 0;
+ } else if (stream->wrapper->is_url) {
+ php_stream_close(stream);
+ php_error(E_WARNING, "remote cafile streams are disabled for security purposes");
+ return 0;
+ }
+
+ cert_start: {
+ line = php_stream_get_line(stream, NULL, 0, &line_len);
+ if (line == NULL) {
+ goto stream_complete;
+ } else if (strcmp(line, begin_line)) {
+ efree(line);
+ goto cert_start;
+ } else {
+ buffer = BIO_new(BIO_s_mem());
+ buffer_active = 1;
+ }
+ }
+
+ cert_line: {
+ BIO_puts(buffer, line);
+ efree(line);
+ line = php_stream_get_line(stream, NULL, 0, &line_len);
+ if (line == NULL) {
+ goto stream_complete;
+ } else if (strcmp(line, end_line)) {
+ goto cert_line;
+ } else {
+ goto add_cert;
+ }
+ }
+
+ add_cert: {
+ BIO_puts(buffer, line);
+ efree(line);
+ cert = PEM_read_bio_X509(buffer, NULL, 0, NULL);
+ BIO_free(buffer);
+ buffer_active = 0;
+ if (cert && X509_STORE_add_cert(cert_store, cert)) {
+ ++certs_added;
+ }
+ goto cert_start;
+ }
+
+ stream_complete: {
+ php_stream_close(stream);
+ if (buffer_active) {
+ BIO_free(buffer);
+ }
+ }
+
+ return certs_added;
+}
+/* }}} */
+
+static int load_verify_locations(SSL_CTX *ctx, php_stream *stream, char *cafile, char *capath TSRMLS_DC) /* {{{ */
+{
+ if (!cafile) {
+ cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile"), 0);
+ cafile = strlen(cafile) ? cafile : NULL;
+ }
+
+ if (!capath) {
+ capath = zend_ini_string("openssl.capath", sizeof("openssl.capath"), 0);
+ capath = strlen(capath) ? capath : NULL;
+ }
+
+ if (cafile || capath) {
+ if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
+ if (cafile && !load_stream_cafile(SSL_CTX_get_cert_store(ctx), cafile TSRMLS_CC)) {
+ return 0;
+ }
+ }
+ } else {
+ php_openssl_netstream_data_t *sslsock;
+ sslsock = (php_openssl_netstream_data_t*)stream->abstract;
+ if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Unable to set default verify locations and no CA settings specified");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+/* }}} */
+
SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */
{
zval **val = NULL;
@@ -5217,29 +5321,8 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
GET_VER_OPT_STRING("cafile", cafile);
GET_VER_OPT_STRING("capath", capath);
- if (!cafile) {
- zend_bool exists = 1;
- cafile = zend_ini_string_ex("openssl.cafile", sizeof("openssl.cafile"), 0, &exists);
- }
-
- if (!capath) {
- zend_bool exists = 1;
- capath = zend_ini_string_ex("openssl.capath", sizeof("openssl.capath"), 0, &exists);
- }
-
- if (cafile || capath) {
- if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set verify locations `%s' `%s'", cafile, capath);
- return NULL;
- }
- } else {
- php_openssl_netstream_data_t *sslsock;
- sslsock = (php_openssl_netstream_data_t*)stream->abstract;
- if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "Unable to set default verify locations and no CA settings specified");
- return NULL;
- }
+ if (!load_verify_locations(ctx, stream, cafile, capath TSRMLS_CC)) {
+ return NULL;
}
if (GET_VER_OPT("verify_depth")) {
diff --git a/ext/openssl/tests/bug65538.phar b/ext/openssl/tests/bug65538.phar
new file mode 100644
index 0000000000..ae0bd29c6e
--- /dev/null
+++ b/ext/openssl/tests/bug65538.phar
Binary files differ
diff --git a/ext/openssl/tests/bug65538_001.phpt b/ext/openssl/tests/bug65538_001.phpt
new file mode 100644
index 0000000000..45a0203731
--- /dev/null
+++ b/ext/openssl/tests/bug65538_001.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Bug #65538 SSL context "cafile" supports stream wrappers
+--SKIPIF--
+<?php
+if (!extension_loaded('openssl')) die('skip, openssl required');
+if (!extension_loaded('pcntl')) die('skip, pcntl required');
+?>
+--FILE--
+<?php
+$serverCtx = stream_context_create(['ssl' => [
+ 'local_cert' => __DIR__ . '/bug54992.pem'
+]]);
+$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
+$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $serverFlags, $serverCtx);
+
+$pid = pcntl_fork();
+
+if ($pid == -1) {
+ die('could not fork');
+} else if ($pid) {
+ $clientCtx = stream_context_create(['ssl' => [
+ 'cafile' => 'file://' . __DIR__ . '/bug54992-ca.pem',
+ 'CN_match' => 'bug54992.local'
+ ]]);
+ $html = file_get_contents('https://127.0.0.1:64321', false, $clientCtx);
+ var_dump($html);
+} else {
+ @pcntl_wait($status);
+
+ $client = @stream_socket_accept($server);
+ if ($client) {
+ $in = '';
+ while (!preg_match('/\r?\n\r?\n/', $in)) {
+ $in .= fread($client, 2048);
+ }
+ $response = <<<EOS
+HTTP/1.0 200 OK
+Content-Type: text/plain
+Content-Length: 12
+Connection: close
+
+Hello World!
+EOS;
+
+ fwrite($client, $response);
+ fclose($client);
+ }
+}
+?>
+--EXPECTF--
+string(12) "Hello World!"
diff --git a/ext/openssl/tests/bug65538_002.phpt b/ext/openssl/tests/bug65538_002.phpt
new file mode 100644
index 0000000000..05c2f0a26a
--- /dev/null
+++ b/ext/openssl/tests/bug65538_002.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #65538 SSL context "cafile" disallows URL stream wrappers
+--SKIPIF--
+<?php
+if (!extension_loaded('openssl')) die('skip, openssl required');
+if (!extension_loaded('pcntl')) die('skip, pcntl required');
+?>
+--FILE--
+<?php
+$clientCtx = stream_context_create(['ssl' => [
+ 'cafile' => 'http://curl.haxx.se/ca/cacert.pem'
+]]);
+file_get_contents('https://github.com', false, $clientCtx);
+?>
+--EXPECTF--
+Warning: remote cafile streams are disabled for security purposes in %s on line %d
+
+Warning: file_get_contents(): failed to create an SSL handle in %s on line %d
+
+Warning: file_get_contents(): Failed to enable crypto in %s on line %d
+
+Warning: file_get_contents(%s): failed to open stream: operation failed in %s on line %d
diff --git a/ext/openssl/tests/bug65538_003.phpt b/ext/openssl/tests/bug65538_003.phpt
new file mode 100644
index 0000000000..c522d029b5
--- /dev/null
+++ b/ext/openssl/tests/bug65538_003.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Bug #65538 SSL context "cafile" supports phar wrapper
+--SKIPIF--
+<?php
+if (!extension_loaded('openssl')) die('skip, openssl required');
+if (!extension_loaded('pcntl')) die('skip, pcntl required');
+if (!extension_loaded('phar')) die('skip, phar required');
+?>
+--FILE--
+<?php
+$serverCtx = stream_context_create(['ssl' => [
+ 'local_cert' => __DIR__ . '/bug54992.pem'
+]]);
+$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
+$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $serverFlags, $serverCtx);
+
+$pid = pcntl_fork();
+
+if ($pid == -1) {
+ die('could not fork');
+} else if ($pid) {
+ $clientCtx = stream_context_create(['ssl' => [
+ 'cafile' => 'phar://' . __DIR__ . '/bug65538.phar/bug54992-ca.pem',
+ 'CN_match' => 'bug54992.local'
+ ]]);
+ $html = file_get_contents('https://127.0.0.1:64321', false, $clientCtx);
+ var_dump($html);
+} else {
+ @pcntl_wait($status);
+
+ $client = @stream_socket_accept($server);
+ if ($client) {
+ $in = '';
+ while (!preg_match('/\r?\n\r?\n/', $in)) {
+ $in .= fread($client, 2048);
+ }
+ $response = <<<EOS
+HTTP/1.0 200 OK
+Content-Type: text/plain
+Content-Length: 12
+Connection: close
+
+Hello World!
+EOS;
+
+ fwrite($client, $response);
+ fclose($client);
+ }
+}
+?>
+--EXPECTF--
+string(12) "Hello World!"