Prevent unexpected array entry conversion when reading key

When passing an array, the key entry can get converted to a string if it
is an object, but this actually modifies the original array entry.
The test originally outputted:

```
array(2) {
  [0]=>
  string(...) => ...
  [1]=>
  string(0) ""
}
```

This is unexpected. Use zval_try_get_string() to prevent this behaviour.

Closes GH-16693.
This commit is contained in:
Niels Dossche 2024-11-03 21:58:06 +01:00
parent 065bde1e13
commit ac8d0e57d9
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
3 changed files with 42 additions and 6 deletions

3
NEWS
View file

@ -8,6 +8,9 @@ PHP NEWS
- FPM: - FPM:
. Fixed GH-16432 (PHP-FPM 8.2 SIGSEGV in fpm_get_status). (Jakub Zelenka) . Fixed GH-16432 (PHP-FPM 8.2 SIGSEGV in fpm_get_status). (Jakub Zelenka)
- OpenSSL:
. Prevent unexpected array entry conversion when reading key. (nielsdos)
- PDO: - PDO:
. Fixed memory leak of `setFetchMode()`. (SakiTakamachi) . Fixed memory leak of `setFetchMode()`. (SakiTakamachi)

View file

@ -3577,19 +3577,21 @@ static EVP_PKEY *php_openssl_pkey_from_zval(
if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) { if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) {
TMP_CLEAN; TMP_CLEAN;
} }
if (!try_convert_to_string(val)) { zend_string *val_str = zval_try_get_string(val);
if (!val_str) {
TMP_CLEAN; TMP_CLEAN;
} }
if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { if (ZSTR_LEN(val_str) > 7 && memcmp(ZSTR_VAL(val_str), "file://", sizeof("file://") - 1) == 0) {
if (!php_openssl_check_path_str(Z_STR_P(val), file_path, arg_num)) { if (!php_openssl_check_path_str(val_str, file_path, arg_num)) {
zend_string_release_ex(val_str, false);
TMP_CLEAN; TMP_CLEAN;
} }
is_file = true; is_file = true;
} }
/* it's an X509 file/cert of some kind, and we need to extract the data from that */ /* it's an X509 file/cert of some kind, and we need to extract the data from that */
if (public_key) { if (public_key) {
cert = php_openssl_x509_from_str(Z_STR_P(val), arg_num, false, NULL); cert = php_openssl_x509_from_str(val_str, arg_num, false, NULL);
if (cert) { if (cert) {
free_cert = 1; free_cert = 1;
@ -3599,10 +3601,11 @@ static EVP_PKEY *php_openssl_pkey_from_zval(
if (is_file) { if (is_file) {
in = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); in = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
} else { } else {
in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); in = BIO_new_mem_buf(ZSTR_VAL(val_str), (int)ZSTR_LEN(val_str));
} }
if (in == NULL) { if (in == NULL) {
php_openssl_store_errors(); php_openssl_store_errors();
zend_string_release_ex(val_str, false);
TMP_CLEAN; TMP_CLEAN;
} }
key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL); key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
@ -3615,10 +3618,11 @@ static EVP_PKEY *php_openssl_pkey_from_zval(
if (is_file) { if (is_file) {
in = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); in = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
} else { } else {
in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); in = BIO_new_mem_buf(ZSTR_VAL(val_str), (int)ZSTR_LEN(val_str));
} }
if (in == NULL) { if (in == NULL) {
zend_string_release_ex(val_str, false);
TMP_CLEAN; TMP_CLEAN;
} }
if (passphrase == NULL) { if (passphrase == NULL) {
@ -3631,6 +3635,8 @@ static EVP_PKEY *php_openssl_pkey_from_zval(
} }
BIO_free(in); BIO_free(in);
} }
zend_string_release_ex(val_str, false);
} }
if (key == NULL) { if (key == NULL) {

View file

@ -0,0 +1,27 @@
--TEST--
openssl_pkey_export_to_file object to string conversion
--EXTENSIONS--
openssl
--FILE--
<?php
class Test {
public function __toString(): string {
return "file://" . __DIR__ . "/private_rsa_1024.key";
}
}
$path = new Test;
$key = [$path, ""];
@openssl_pkey_export_to_file($key, str_repeat("a", 10000), passphrase: "");
var_dump($key);
?>
--EXPECT--
array(2) {
[0]=>
object(Test)#1 (0) {
}
[1]=>
string(0) ""
}