Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ PHP NEWS
preloaded trait). (iliaal)

- OpenSSL:
. Added $salt_length parameter to openssl_sign() and openssl_verify() with
new OPENSSL_RSA_PSS_SALTLEN_* constants. (Jakub Zelenka)
. Fixed timeout for supplemental read at end of a blocking stream in SSL
stream wrapper. (ilutov)
. Fixed stream_socket_get_crypto_status() after supplemental read. (ilutov)
Expand Down
9 changes: 9 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,10 @@ PHP 8.6 UPGRADE NOTES
- OpenSSL:
. Output of openssl_x509_parse() contains criticalExtensions listing all
critical certificate extensions.
. openssl_sign() and openssl_verify() now have an additional optional
argument $salt_length that allows controlling the RSA-PSS salt length
when OPENSSL_PKCS1_PSS_PADDING is used. It accepts an explicit length or
one of the new OPENSSL_RSA_PSS_SALTLEN_* constants.

- PDO_DBLIB:
. When using persistent connections, there is now a liveness check in the
Expand Down Expand Up @@ -513,6 +517,11 @@ PHP 8.6 UPGRADE NOTES
. CURL_SEEKFUNC_FAIL.
. CURL_SEEKFUNC_CANTSEEK.

- OpenSSL:
. OPENSSL_RSA_PSS_SALTLEN_DIGEST.
. OPENSSL_RSA_PSS_SALTLEN_AUTO.
. OPENSSL_RSA_PSS_SALTLEN_MAX.

- Sockets:
. TCP_USER_TIMEOUT (Linux only).
. AF_UNSPEC.
Expand Down
3 changes: 3 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ PHP 8.6 INTERNALS UPGRADE NOTES
(sendfile, splice, copy_file_range, TransmitFile), and is now used by
php_stream_copy_to_stream_ex(). The mmap-based copy fallback was removed.
. Added zend_string_equals_cstr_ci().
. Added zend_cstr_append_char(), zend_cstr_concat(), and
zend_cstr_concat3() as helper functions to allocate NUL-terminated raw C
strings from one or more buffers.
. Added zend_string_ends_with() and related variants.
. Added trait support for internal classes.

Expand Down
31 changes: 31 additions & 0 deletions Zend/tests/gh22849.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
PHP 8.6 error_include_args=1 mishandled for include()
--INI--
error_include_args=On
--FILE--
<?php

function foo() {
include("does not exist");
include_once("does not exist");
require("does not exist");
}

foo(1, 2);
?>
--EXPECTF--
Warning: include('does not exist'): Failed to open stream: No such file or directory in %s on line %d

Warning: include('does not exist'): Failed opening 'does not exist' for inclusion (include_path='%s') in %s on line %d

Warning: include_once('does not exist'): Failed to open stream: No such file or directory in %s on line %d

Warning: include_once('does not exist'): Failed opening 'does not exist' for inclusion (include_path='%s') in %s on line %d

Warning: require('does not exist'): Failed to open stream: No such file or directory in %s on line %d

Fatal error: Uncaught Error: Failed opening required 'does not exist' (include_path='%s') in %s:%d
Stack trace:
#0 %s(%d): foo(1, 2)
#1 {main}
thrown in %s on line %d
13 changes: 13 additions & 0 deletions Zend/zend_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,19 @@ ZEND_API zend_string *zend_trace_function_args_to_string(const HashTable *frame)
/* {{{ Gets the currently executing function's arguments as a string. Used by php_verror. */
ZEND_API zend_string *zend_trace_current_function_args_string(void) {
zend_string *dynamic_params = NULL;
/* Special case: require_once/include_once aren't functions, but we
* want to capture their arguments anyways, for i.e. file not found.
*/
zend_execute_data *execute_data = EG(current_execute_data);
if (execute_data && execute_data->func
&& ZEND_USER_CODE(execute_data->func->common.type)
&& (execute_data->opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
zval *inc_filename = RT_CONSTANT(execute_data->opline, execute_data->opline->op1);
smart_str str = {0};
build_trace_args(inc_filename, &str);
return smart_str_extract(&str);
}

/* get a backtrace to snarf function args */
zval backtrace;
zend_fetch_debug_backtrace(&backtrace, /* skip_last */ 0, /* options */ 0, /* limit */ 1);
Expand Down
35 changes: 32 additions & 3 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4525,6 +4525,27 @@ static zend_result php_openssl_setup_rsa_padding(EVP_PKEY_CTX *pctx, EVP_PKEY *p
return SUCCESS;
}

static zend_result php_openssl_setup_rsa_pss_salt_length(EVP_PKEY_CTX *pctx, EVP_PKEY *pkey, zend_long padding, zend_long salt_length)
{
/* Only apply if using PSS padding */
if (padding != RSA_PKCS1_PSS_PADDING) {
return SUCCESS;
}

/* Only apply to RSA keys */
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA && EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA_PSS) {
return SUCCESS;
}

if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, (int)salt_length) <= 0) {
php_openssl_store_errors();
php_error_docref(NULL, E_WARNING, "Could not set RSA-PSS salt length");
return FAILURE;
}

return SUCCESS;
}

/* {{{ Signs data */
PHP_FUNCTION(openssl_sign)
{
Expand All @@ -4538,16 +4559,18 @@ PHP_FUNCTION(openssl_sign)
zend_long method_long = OPENSSL_ALGO_SHA1;
const EVP_MD *mdtype;
zend_long padding = 0;
zend_long salt_length = RSA_PSS_SALTLEN_AUTO;
EVP_PKEY_CTX *pctx;
bool can_default_digest = ZEND_THREEWAY_COMPARE(PHP_OPENSSL_API_VERSION, 0x30000) >= 0;

ZEND_PARSE_PARAMETERS_START(3, 5)
ZEND_PARSE_PARAMETERS_START(3, 6)
Z_PARAM_STRING(data, data_len)
Z_PARAM_ZVAL(signature)
Z_PARAM_ZVAL(key)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_LONG(method_str, method_long)
Z_PARAM_LONG(padding)
Z_PARAM_LONG(salt_length)
ZEND_PARSE_PARAMETERS_END();

pkey = php_openssl_pkey_from_zval(key, 0, "", 0, 3);
Expand All @@ -4568,12 +4591,14 @@ PHP_FUNCTION(openssl_sign)
php_error_docref(NULL, E_WARNING, "Unknown digest algorithm");
RETURN_FALSE;
}
PHP_OPENSSL_CHECK_LONG_TO_INT(salt_length, salt_length, 6);

md_ctx = EVP_MD_CTX_create();
size_t siglen;
if (md_ctx != NULL &&
EVP_DigestSignInit(md_ctx, &pctx, mdtype, NULL, pkey) &&
php_openssl_setup_rsa_padding(pctx, pkey, padding) == SUCCESS &&
php_openssl_setup_rsa_pss_salt_length(pctx, pkey, padding, salt_length) == SUCCESS &&
EVP_DigestSign(md_ctx, NULL, &siglen, (unsigned char*)data, data_len) &&
(sigbuf = zend_string_alloc(siglen, 0)) != NULL &&
EVP_DigestSign(md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen, (unsigned char*)data, data_len)) {
Expand Down Expand Up @@ -4607,19 +4632,22 @@ PHP_FUNCTION(openssl_verify)
zend_string *method_str = NULL;
zend_long method_long = OPENSSL_ALGO_SHA1;
zend_long padding = 0;
zend_long salt_length = RSA_PSS_SALTLEN_AUTO;
EVP_PKEY_CTX *pctx;
bool can_default_digest = ZEND_THREEWAY_COMPARE(PHP_OPENSSL_API_VERSION, 0x30000) >= 0;

ZEND_PARSE_PARAMETERS_START(3, 5)
ZEND_PARSE_PARAMETERS_START(3, 6)
Z_PARAM_STRING(data, data_len)
Z_PARAM_STRING(signature, signature_len)
Z_PARAM_ZVAL(key)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_LONG(method_str, method_long)
Z_PARAM_LONG(padding)
Z_PARAM_LONG(salt_length)
ZEND_PARSE_PARAMETERS_END();

PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(signature_len, signature, 2);
PHP_OPENSSL_CHECK_LONG_TO_INT(salt_length, salt_length, 6);

if (method_str) {
mdtype = php_openssl_get_evp_md_by_name(ZSTR_VAL(method_str));
Expand Down Expand Up @@ -4648,7 +4676,8 @@ PHP_FUNCTION(openssl_verify)
}

if (!EVP_DigestVerifyInit(md_ctx, &pctx, mdtype, NULL, pkey) ||
php_openssl_setup_rsa_padding(pctx, pkey, padding) == FAILURE) {
php_openssl_setup_rsa_padding(pctx, pkey, padding) == FAILURE ||
php_openssl_setup_rsa_pss_salt_length(pctx, pkey, padding, salt_length) == FAILURE) {
php_openssl_store_errors();
err = -1;
goto cleanup;
Expand Down
20 changes: 18 additions & 2 deletions ext/openssl/openssl.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,22 @@ public function __unserialize(array $data): void {}
*/
const OPENSSL_PKCS1_PSS_PADDING = UNKNOWN;

/**
* @var int
* @cvalue RSA_PSS_SALTLEN_DIGEST
*/
const OPENSSL_RSA_PSS_SALTLEN_DIGEST = UNKNOWN;
/**
* @var int
* @cvalue RSA_PSS_SALTLEN_AUTO
*/
const OPENSSL_RSA_PSS_SALTLEN_AUTO = UNKNOWN;
/**
* @var int
* @cvalue RSA_PSS_SALTLEN_MAX
*/
const OPENSSL_RSA_PSS_SALTLEN_MAX = UNKNOWN;

/* Informational stream wrapper constants */

/**
Expand Down Expand Up @@ -679,10 +695,10 @@ function openssl_error_string(): string|false {}
* @param string $signature
* @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key
*/
function openssl_sign(string $data, &$signature, #[\SensitiveParameter] $private_key, string|int $algorithm = OPENSSL_ALGO_SHA1, int $padding = 0): bool {}
function openssl_sign(string $data, &$signature, #[\SensitiveParameter] $private_key, string|int $algorithm = OPENSSL_ALGO_SHA1, int $padding = 0, int $salt_length = OPENSSL_RSA_PSS_SALTLEN_AUTO): bool {}

/** @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $public_key */
function openssl_verify(string $data, string $signature, $public_key, string|int $algorithm = OPENSSL_ALGO_SHA1, int $padding = 0): int|false {}
function openssl_verify(string $data, string $signature, $public_key, string|int $algorithm = OPENSSL_ALGO_SHA1, int $padding = 0, int $salt_length = OPENSSL_RSA_PSS_SALTLEN_AUTO): int|false {}

/**
* @param string $sealed_data
Expand Down
7 changes: 6 additions & 1 deletion ext/openssl/openssl_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion ext/openssl/tests/openssl_sign_basic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ openssl
$data = "Testing openssl_sign()";
$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
$wrong = "wrong";

var_dump(openssl_sign($data, $sign1, $privkey, OPENSSL_ALGO_SHA256));
var_dump(bin2hex($sign1));
var_dump(openssl_sign($data, $sign2, $privkey, OPENSSL_ALGO_SHA256));
Expand All @@ -17,6 +16,10 @@ var_dump(strlen($sign1));
var_dump(openssl_sign($data, $sign2, $privkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING));
var_dump(strlen($sign2));
var_dump($sign1 === $sign2);
var_dump(openssl_sign($data, $sign3, $privkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, OPENSSL_RSA_PSS_SALTLEN_DIGEST));
var_dump(strlen($sign3));
var_dump(openssl_sign($data, $sign4, $privkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, 32));
var_dump(strlen($sign4));
var_dump(openssl_sign($data, $sign, $wrong));
?>
--EXPECTF--
Expand All @@ -29,6 +32,10 @@ int(128)
bool(true)
int(128)
bool(false)
bool(true)
int(128)
bool(true)
int(128)

Warning: openssl_sign(): Supplied key param cannot be coerced into a private key in %s on line %d
bool(false)
14 changes: 14 additions & 0 deletions ext/openssl/tests/openssl_verify_basic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ $wrong = "wrong";
openssl_sign($data, $sign, $privkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING);
var_dump(openssl_verify($data, $sign, $pubkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING));
var_dump(openssl_verify($data, $sign, $pubkey, OPENSSL_ALGO_SHA256));
openssl_sign($data, $sign_pss, $privkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, OPENSSL_RSA_PSS_SALTLEN_DIGEST);
var_dump(openssl_verify($data, $sign_pss, $pubkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, OPENSSL_RSA_PSS_SALTLEN_DIGEST));
var_dump(openssl_verify($data, $sign_pss, $pubkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, 32));
var_dump(openssl_verify($data, $sign_pss, $pubkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, OPENSSL_RSA_PSS_SALTLEN_AUTO));
var_dump(openssl_verify($data, $sign_pss, $pubkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, 20));
openssl_sign($data, $sign_pss, $privkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, OPENSSL_RSA_PSS_SALTLEN_MAX);
var_dump(openssl_verify($data, $sign_pss, $pubkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, OPENSSL_RSA_PSS_SALTLEN_MAX));
var_dump(openssl_verify($data, $sign_pss, $pubkey, OPENSSL_ALGO_SHA256, OPENSSL_PKCS1_PSS_PADDING, OPENSSL_RSA_PSS_SALTLEN_DIGEST));
openssl_sign($data, $sign, $privkey, OPENSSL_ALGO_SHA256);
var_dump(openssl_verify($data, $sign, $pubkey, OPENSSL_ALGO_SHA256));
var_dump(openssl_verify($data, $sign, $privkey, OPENSSL_ALGO_SHA256));
Expand All @@ -24,6 +32,12 @@ var_dump(openssl_verify($wrong, $sign, $pubkey, OPENSSL_ALGO_SHA256));
int(1)
int(0)
int(1)
int(1)
int(1)
int(0)
int(1)
int(0)
int(1)

Warning: openssl_verify(): Supplied key param cannot be coerced into a public key in %s on line %d
bool(false)
Expand Down
2 changes: 2 additions & 0 deletions ext/zip/php_zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static bool php_zip_set_file_comment(struct zip *za, zip_uint64_t index, const c
# define add_ascii_assoc_string add_assoc_string
# define add_ascii_assoc_long add_assoc_long

#ifdef HAVE_ENCRYPTION
static bool php_zip_file_set_encryption(struct zip *intern, zend_long index, zend_long method, char *password) {
// FIXME: is a workaround to reset/free the password in case of consecutive calls.
// when libzip 1.11.5 is available, we can save this call in this case.
Expand All @@ -92,6 +93,7 @@ static bool php_zip_file_set_encryption(struct zip *intern, zend_long index, zen

return (zip_file_set_encryption(intern, (zip_uint64_t)index, (zip_uint16_t)method, password) == 0);
}
#endif

/* Flatten a path by making a relative path (to .)*/
static char * php_zip_make_relative_path(char *path, size_t path_len) /* {{{ */
Expand Down