mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Fix bug #80770: openssl cafile not used in SNI SSL_CTX
The issue is about not being able to connect as cafile for SNI is not used in its SSL context. This sets it up so it is possible to capture the client certificate which is only possible when verify_peer is true. Closes GH-18893
This commit is contained in:
parent
71472268c0
commit
6b2b60f683
3 changed files with 102 additions and 5 deletions
4
NEWS
4
NEWS
|
@ -34,6 +34,10 @@ PHP NEWS
|
|||
. Fixed bug GH-14082 (Segmentation fault on unknown address 0x600000000018
|
||||
in ext/opcache/jit/zend_jit.c). (nielsdos)
|
||||
|
||||
- OpenSSL:
|
||||
. Fixed bug #80770 (It is not possible to get client peer certificate with
|
||||
stream_socket_server). (Jakub Zelenka)
|
||||
|
||||
- PCNTL:
|
||||
. Fixed bug GH-18958 (Fatal error during shutdown after pcntl_rfork() or
|
||||
pcntl_forkx() with zend-max-execution-timers). (Arnaud)
|
||||
|
|
83
ext/openssl/tests/bug80770.phpt
Normal file
83
ext/openssl/tests/bug80770.phpt
Normal file
|
@ -0,0 +1,83 @@
|
|||
--TEST--
|
||||
Bug #80770: SNI_server_certs does not inherit peer verification options
|
||||
--EXTENSIONS--
|
||||
openssl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists("proc_open")) die("skip no proc_open");
|
||||
if (OPENSSL_VERSION_NUMBER < 0x10101000) die("skip OpenSSL v1.1.1 required");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$clientCertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug80770_client.pem.tmp';
|
||||
$caCertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug80770_ca.pem.tmp';
|
||||
|
||||
$serverCode = <<<'CODE'
|
||||
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
|
||||
$ctx = stream_context_create(['ssl' => [
|
||||
'SNI_server_certs' => [
|
||||
"cs.php.net" => __DIR__ . "/sni_server_cs.pem",
|
||||
"uk.php.net" => __DIR__ . "/sni_server_uk.pem",
|
||||
"us.php.net" => __DIR__ . "/sni_server_us.pem"
|
||||
],
|
||||
'verify_peer' => true,
|
||||
'cafile' => '%s',
|
||||
'capture_peer_cert' => true,
|
||||
'verify_peer_name' => false,
|
||||
'security_level' => 0,
|
||||
]]);
|
||||
$server = stream_socket_server('tcp://127.0.0.1:0', $errno, $errstr, $flags, $ctx);
|
||||
phpt_notify_server_start($server);
|
||||
|
||||
$client = stream_socket_accept($server, 30);
|
||||
if ($client) {
|
||||
$success = stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_SERVER);
|
||||
if ($success) {
|
||||
$options = stream_context_get_options($client);
|
||||
$hasCert = isset($options['ssl']['peer_certificate']);
|
||||
phpt_notify(message: $hasCert ? "CLIENT_CERT_CAPTURED" : "NO_CLIENT_CERT");
|
||||
} else {
|
||||
phpt_notify(message: "TLS_HANDSHAKE_FAILED");
|
||||
}
|
||||
} else {
|
||||
phpt_notify(message: "ACCEPT_FAILED");
|
||||
}
|
||||
CODE;
|
||||
$serverCode = sprintf($serverCode, $caCertFile);
|
||||
|
||||
$clientCode = <<<'CODE'
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
$ctx = stream_context_create(['ssl' => [
|
||||
'verify_peer' => false,
|
||||
'verify_peer_name' => false,
|
||||
'local_cert' => '%s',
|
||||
'peer_name' => 'cs.php.net',
|
||||
'security_level' => 0,
|
||||
]]);
|
||||
$client = stream_socket_client("tcp://{{ ADDR }}", $errno, $errstr, 30, $flags, $ctx);
|
||||
if ($client) {
|
||||
stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
|
||||
}
|
||||
|
||||
$result = phpt_wait();
|
||||
echo trim($result);
|
||||
CODE;
|
||||
$clientCode = sprintf($clientCode, $clientCertFile);
|
||||
|
||||
include 'CertificateGenerator.inc';
|
||||
|
||||
// Generate CA and client certificate signed by that CA
|
||||
$certificateGenerator = new CertificateGenerator();
|
||||
$certificateGenerator->saveCaCert($caCertFile);
|
||||
$certificateGenerator->saveNewCertAsFileWithKey('Bug80770 Test Client', $clientCertFile);
|
||||
|
||||
include 'ServerClientTestCase.inc';
|
||||
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug80770_client.pem.tmp');
|
||||
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug80770_ca.pem.tmp');
|
||||
?>
|
||||
--EXPECTF--
|
||||
CLIENT_CERT_CAPTURED
|
|
@ -1443,7 +1443,8 @@ static SSL_CTX *php_openssl_create_sni_server_ctx(char *cert_path, char *key_pat
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_result php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */
|
||||
static zend_result php_openssl_enable_server_sni(
|
||||
php_stream *stream, php_openssl_netstream_data_t *sslsock, bool verify_peer)
|
||||
{
|
||||
zval *val;
|
||||
zval *current;
|
||||
|
@ -1564,6 +1565,12 @@ static zend_result php_openssl_enable_server_sni(php_stream *stream, php_openssl
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
if (!verify_peer) {
|
||||
php_openssl_disable_peer_verification(ctx, stream);
|
||||
} else if (FAILURE == php_openssl_enable_peer_verification(ctx, stream)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
sslsock->sni_certs[i].name = pestrdup(ZSTR_VAL(key), php_stream_is_persistent(stream));
|
||||
sslsock->sni_certs[i].ctx = ctx;
|
||||
++i;
|
||||
|
@ -1574,7 +1581,6 @@ static zend_result php_openssl_enable_server_sni(php_stream *stream, php_openssl
|
|||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void php_openssl_enable_client_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */
|
||||
{
|
||||
|
@ -1666,6 +1672,7 @@ zend_result php_openssl_setup_crypto(php_stream *stream,
|
|||
char *cipherlist = NULL;
|
||||
char *alpn_protocols = NULL;
|
||||
zval *val;
|
||||
bool verify_peer = false;
|
||||
|
||||
if (sslsock->ssl_handle) {
|
||||
if (sslsock->s.is_blocked) {
|
||||
|
@ -1717,8 +1724,11 @@ zend_result php_openssl_setup_crypto(php_stream *stream,
|
|||
|
||||
if (GET_VER_OPT("verify_peer") && !zend_is_true(val)) {
|
||||
php_openssl_disable_peer_verification(sslsock->ctx, stream);
|
||||
} else if (FAILURE == php_openssl_enable_peer_verification(sslsock->ctx, stream)) {
|
||||
return FAILURE;
|
||||
} else {
|
||||
verify_peer = true;
|
||||
if (FAILURE == php_openssl_enable_peer_verification(sslsock->ctx, stream)) {
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* callback for the passphrase (for localcert) */
|
||||
|
@ -1819,7 +1829,7 @@ zend_result php_openssl_setup_crypto(php_stream *stream,
|
|||
|
||||
#ifdef HAVE_TLS_SNI
|
||||
/* Enable server-side SNI */
|
||||
if (!sslsock->is_client && php_openssl_enable_server_sni(stream, sslsock) == FAILURE) {
|
||||
if (!sslsock->is_client && php_openssl_enable_server_sni(stream, sslsock, verify_peer) == FAILURE) {
|
||||
return FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue