diff options
| -rwxr-xr-x | ext/openssl/openssl.c | 135 | ||||
| -rw-r--r-- | ext/openssl/tests/bug65538.phar | bin | 0 -> 9402 bytes | |||
| -rw-r--r-- | ext/openssl/tests/bug65538_001.phpt | 51 | ||||
| -rw-r--r-- | ext/openssl/tests/bug65538_002.phpt | 22 | ||||
| -rw-r--r-- | ext/openssl/tests/bug65538_003.phpt | 52 |
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 Binary files differnew file mode 100644 index 0000000000..ae0bd29c6e --- /dev/null +++ b/ext/openssl/tests/bug65538.phar 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!" |
