Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b2f3472
Fix crash in openssl_digest() when EVP_MD_CTX_create() fails
ndossche Jan 23, 2026
d0d9183
Fix crash in openssl_pkey_export() when BIO_new() fails
ndossche Jan 23, 2026
5f9b6ed
Fix crash in openssl_pkcs12_read() when BIO_new() fails
ndossche Jan 23, 2026
1ef9aa7
Fix crash in php_openssl_create_sni_server_ctx() when SSL_CTX_new() f…
ndossche Jan 24, 2026
513f129
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Apr 3, 2026
5405e2b
Merge branch 'PHP-8.5'
ndossche Apr 3, 2026
20903a8
Fix memory leak on error path in openssl_open()
ndossche Jan 27, 2026
2004b70
Fix missing error propagation in openssl_x509_export_to_file()
ndossche Mar 5, 2026
4bb68c5
Fix memory leaks when adding certificate to store fails
ndossche Jan 24, 2026
1c94175
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Apr 3, 2026
f630a69
Merge branch 'PHP-8.5'
ndossche Apr 3, 2026
1c94632
Fix SKIPIF of openssl_password.phpt (#20941)
ndossche Apr 3, 2026
7831244
openssl: Fix missing error propagation in openssl_x509_export() (#21375)
ndossche Apr 3, 2026
4a16d22
openssl: Fix error propagation in csr exports (#21403)
ndossche Apr 3, 2026
4d544e4
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Apr 3, 2026
a0e679e
Merge branch 'PHP-8.5'
ndossche Apr 3, 2026
5684949
Fix error check on X509V3_EXT_print()
ndossche Jan 27, 2026
e474d3c
Fix crash in openssl_pkey_get_details() when BIO_new() fails
ndossche Jan 23, 2026
c4e70a2
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Apr 3, 2026
fc55723
Merge branch 'PHP-8.5'
ndossche Apr 3, 2026
8c11370
Fix crash when ASN1_STRING_to_UTF8() fails
ndossche Jan 23, 2026
8b031ea
Fix error check on X509_set_subject_name()
ndossche Jan 24, 2026
a8b7665
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Apr 3, 2026
36c0554
Merge branch 'PHP-8.5'
ndossche Apr 3, 2026
0f38bfd
Fix GH-21617: sni_server self signed certifcate expired
bukka Apr 3, 2026
c63547b
Merge branch 'PHP-8.2' into PHP-8.3
bukka Apr 3, 2026
178a30b
Fix SNI tests for bugs #80770 and #74796
bukka Apr 3, 2026
449bfaf
Merge branch 'PHP-8.3' into PHP-8.4
bukka Apr 3, 2026
1d8643d
Add back sni_server_ca for expired cert test
bukka Apr 3, 2026
0f2b93e
Merge branch 'PHP-8.4' into PHP-8.5
bukka Apr 3, 2026
b7c855f
Merge branch 'PHP-8.5'
bukka Apr 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 28 additions & 22 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,14 +562,11 @@ PHP_FUNCTION(openssl_x509_export_to_file)

bio_out = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
if (bio_out) {
if (!notext && !X509_print(bio_out, cert)) {
php_openssl_store_errors();
}
if (!PEM_write_bio_X509(bio_out, cert)) {
if ((notext || X509_print(bio_out, cert)) && PEM_write_bio_X509(bio_out, cert)) {
RETVAL_TRUE;
} else {
php_openssl_store_errors();
}

RETVAL_TRUE;
} else {
php_openssl_store_errors();
php_error_docref(NULL, E_WARNING, "Error opening file %s", file_path);
Expand Down Expand Up @@ -864,8 +861,7 @@ PHP_FUNCTION(openssl_x509_export)
}
if (!notext && !X509_print(bio_out, cert)) {
php_openssl_store_errors();
}
if (PEM_write_bio_X509(bio_out, cert)) {
} else if (PEM_write_bio_X509(bio_out, cert)) {
BUF_MEM *bio_buf;

BIO_get_mem_ptr(bio_out, &bio_buf);
Expand Down Expand Up @@ -1156,7 +1152,7 @@ PHP_FUNCTION(openssl_x509_parse)
goto err_subitem;
}
}
else if (X509V3_EXT_print(bio_out, extension, 0, 0)) {
else if (X509V3_EXT_print(bio_out, extension, 0, 0) > 0) {
BIO_get_mem_ptr(bio_out, &bio_buf);
add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
} else {
Expand Down Expand Up @@ -1518,7 +1514,7 @@ PHP_FUNCTION(openssl_pkcs12_read)

if (cert) {
bio_out = BIO_new(BIO_s_mem());
if (PEM_write_bio_X509(bio_out, cert)) {
if (bio_out && PEM_write_bio_X509(bio_out, cert)) {
BUF_MEM *bio_buf;
BIO_get_mem_ptr(bio_out, &bio_buf);
ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
Expand Down Expand Up @@ -1628,9 +1624,9 @@ PHP_FUNCTION(openssl_csr_export_to_file)
bio_out = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
if (bio_out != NULL) {
if (!notext && !X509_REQ_print(bio_out, csr)) {
/* TODO: warn? */
php_openssl_store_errors();
}
if (!PEM_write_bio_X509_REQ(bio_out, csr)) {
} else if (!PEM_write_bio_X509_REQ(bio_out, csr)) {
php_error_docref(NULL, E_WARNING, "Error writing PEM to file %s", file_path);
php_openssl_store_errors();
} else {
Expand Down Expand Up @@ -1679,9 +1675,7 @@ PHP_FUNCTION(openssl_csr_export)
bio_out = BIO_new(BIO_s_mem());
if (!notext && !X509_REQ_print(bio_out, csr)) {
php_openssl_store_errors();
}

if (PEM_write_bio_X509_REQ(bio_out, csr)) {
} else if (PEM_write_bio_X509_REQ(bio_out, csr)) {
BUF_MEM *bio_buf;

BIO_get_mem_ptr(bio_out, &bio_buf);
Expand Down Expand Up @@ -1824,7 +1818,10 @@ PHP_FUNCTION(openssl_csr_sign)
PHP_OPENSSL_ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
}

X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));
if (!X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr))) {
php_openssl_store_errors();
goto cleanup;
}

if (cert == NULL) {
cert = new_cert;
Expand Down Expand Up @@ -2224,6 +2221,10 @@ PHP_FUNCTION(openssl_pkey_export)

if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
bio_out = BIO_new(BIO_s_mem());
if (!bio_out) {
php_openssl_store_errors();
goto cleanup;
}

if (passphrase && req.priv_key_encrypt) {
if (req.priv_key_encrypt_cipher) {
Expand Down Expand Up @@ -2252,6 +2253,7 @@ PHP_FUNCTION(openssl_pkey_export)
php_openssl_store_errors();
}
}
cleanup:
EVP_PKEY_free(key);
BIO_free(bio_out);
PHP_SSL_REQ_DISPOSE(&req);
Expand Down Expand Up @@ -2327,7 +2329,7 @@ PHP_FUNCTION(openssl_pkey_get_details)
EVP_PKEY *pkey = Z_OPENSSL_PKEY_P(key)->pkey;

BIO *out = BIO_new(BIO_s_mem());
if (!PEM_write_bio_PUBKEY(out, pkey)) {
if (!out || !PEM_write_bio_PUBKEY(out, pkey)) {
BIO_free(out);
php_openssl_store_errors();
RETURN_FALSE;
Expand Down Expand Up @@ -4410,18 +4412,20 @@ PHP_FUNCTION(openssl_open)
cipher = php_openssl_get_evp_cipher_by_name(method);
if (!cipher) {
php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
RETURN_FALSE;
RETVAL_FALSE;
goto out_pkey;
}

cipher_iv_len = EVP_CIPHER_iv_length(cipher);
if (cipher_iv_len > 0) {
if (!iv) {
zend_argument_value_error(6, "cannot be null for the chosen cipher algorithm");
RETURN_THROWS();
goto out_pkey;
}
if ((size_t)cipher_iv_len != iv_len) {
php_error_docref(NULL, E_WARNING, "IV length is invalid");
RETURN_FALSE;
RETVAL_FALSE;
goto out_pkey;
}
iv_buf = (unsigned char *)iv;
} else {
Expand All @@ -4443,8 +4447,9 @@ PHP_FUNCTION(openssl_open)
}

efree(buf);
EVP_PKEY_free(pkey);
EVP_CIPHER_CTX_free(ctx);
out_pkey:
EVP_PKEY_free(pkey);
}
/* }}} */

Expand Down Expand Up @@ -4524,7 +4529,8 @@ PHP_FUNCTION(openssl_digest)
sigbuf = zend_string_alloc(siglen, 0);

md_ctx = EVP_MD_CTX_create();
if (EVP_DigestInit(md_ctx, mdtype) &&
if (md_ctx &&
EVP_DigestInit(md_ctx, mdtype) &&
EVP_DigestUpdate(md_ctx, (unsigned char *)data, data_len) &&
EVP_DigestFinal (md_ctx, (unsigned char *)ZSTR_VAL(sigbuf), &siglen)) {
if (raw_output) {
Expand Down
29 changes: 23 additions & 6 deletions ext/openssl/tests/bug74796.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,24 @@ if (substr(PHP_OS, 0, 3) == 'WIN') {
--FILE--
<?php

include 'CertificateGenerator.inc';
$certificateGenerator = new CertificateGenerator();
$caFile = __DIR__ . '/bug74796_ca.pem.tmp';
$csFile = __DIR__ . '/bug74796_cs.pem.tmp';
$ukFile = __DIR__ . '/bug74796_uk.pem.tmp';
$usFile = __DIR__ . '/bug74796_us.pem.tmp';
$certificateGenerator->saveCaCert($caFile);
$certificateGenerator->saveNewCertAsFileWithKey('cs.php.net', $csFile);
$certificateGenerator->saveNewCertAsFileWithKey('uk.php.net', $ukFile);
$certificateGenerator->saveNewCertAsFileWithKey('us.php.net', $usFile);

$serverCode = <<<'CODE'
$serverFlags = 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"
"cs.php.net" => '%s',
"uk.php.net" => '%s',
"us.php.net" => '%s',
]
]]);

Expand All @@ -33,6 +44,7 @@ $serverCode = <<<'CODE'

phpt_wait();
CODE;
$serverCode = sprintf($serverCode, $csFile, $ukFile, $usFile);

$proxyCode = <<<'CODE'
function parse_sni_from_client_hello($data) {
Expand Down Expand Up @@ -134,7 +146,7 @@ CODE;
$clientCode = <<<'CODE'
$clientCtx = stream_context_create([
'ssl' => [
'cafile' => __DIR__ . '/sni_server_ca.pem',
'cafile' => '%s',
'verify_peer' => true,
'verify_peer_name' => true,
],
Expand All @@ -155,16 +167,21 @@ $clientCode = <<<'CODE'

phpt_notify('server');
CODE;
$clientCode = sprintf($clientCode, $caFile);

include 'ServerClientTestCase.inc';
ServerClientTestCase::getInstance()->run($clientCode, [
'server' => $serverCode,
'proxy' => $proxyCode,
'server' => $serverCode,
'proxy' => $proxyCode,
]);
?>
--CLEAN--
<?php
@unlink(__DIR__ . "/bug74796_proxy_sni.log");
@unlink(__DIR__ . '/bug74796_ca.pem.tmp');
@unlink(__DIR__ . '/bug74796_cs.pem.tmp');
@unlink(__DIR__ . '/bug74796_uk.pem.tmp');
@unlink(__DIR__ . '/bug74796_us.pem.tmp');
?>
--EXPECT--
string(19) "Hello from server 0"
Expand Down
31 changes: 18 additions & 13 deletions ext/openssl/tests/bug80770.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,25 @@ if (OPENSSL_VERSION_NUMBER < 0x10101000) die("skip OpenSSL v1.1.1 required");
<?php
$clientCertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug80770_client.pem.tmp';
$caCertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug80770_ca.pem.tmp';
$csFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug80770_cs.pem.tmp';
$ukFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug80770_uk.pem.tmp';
$usFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug80770_us.pem.tmp';

include 'CertificateGenerator.inc';
$certificateGenerator = new CertificateGenerator();
$certificateGenerator->saveCaCert($caCertFile);
$certificateGenerator->saveNewCertAsFileWithKey('cs.php.net', $csFile);
$certificateGenerator->saveNewCertAsFileWithKey('uk.php.net', $ukFile);
$certificateGenerator->saveNewCertAsFileWithKey('us.php.net', $usFile);
$certificateGenerator->saveNewCertAsFileWithKey('Bug80770 Test Client', $clientCertFile);

$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"
"cs.php.net" => '%s',
"uk.php.net" => '%s',
"us.php.net" => '%s',
],
'verify_peer' => true,
'cafile' => '%s',
Expand All @@ -28,7 +39,6 @@ $serverCode = <<<'CODE'
]]);
$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);
Expand All @@ -43,7 +53,7 @@ $serverCode = <<<'CODE'
phpt_notify(message: "ACCEPT_FAILED");
}
CODE;
$serverCode = sprintf($serverCode, $caCertFile);
$serverCode = sprintf($serverCode, $csFile, $ukFile, $usFile, $caCertFile);

$clientCode = <<<'CODE'
$flags = STREAM_CLIENT_CONNECT;
Expand All @@ -58,26 +68,21 @@ $clientCode = <<<'CODE'
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');
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug80770_cs.pem.tmp');
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug80770_uk.pem.tmp');
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug80770_us.pem.tmp');
?>
--EXPECTF--
CLIENT_CERT_CAPTURED
Loading