1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-11054: Reset OpenSSL errors when using a PEM public key

The error happens when the PEM contains a public key, as it will be
first tried to be parsed as a certificate. The parsing as a certificate
fails, which then leads to a corresponding error tracked by PHP with
the next call to php_openssl_store_errors().

This change introduces an error marking to be able to reset the stored
errors to the state before trying the certificate.

Closes GH-11055
This commit is contained in:
Florian Moser
2023-04-10 20:12:31 +02:00
committed by Jakub Zelenka
parent 5690e8baea
commit 4d4b9604ca
7 changed files with 66 additions and 6 deletions

2
NEWS
View File

@@ -118,6 +118,8 @@ PHP NEWS
- OpenSSL:
. Added OPENSSL_CMS_OLDMIMETYPE and PKCS7_NOOLDMIMETYPE contants to switch
between mime content types. (Daniel Kesselberg)
. Fixed GH-11054: Reset OpenSSL errors when using a PEM public key.
(Florian Moser)
- PCNTL:
. SA_ONSTACK is now set for pcntl_signal. (Kévin Dunglas)

View File

@@ -476,6 +476,37 @@ void php_openssl_store_errors(void)
}
/* }}} */
/* {{{ php_openssl_errors_set_mark */
void php_openssl_errors_set_mark(void) {
if (!OPENSSL_G(errors)) {
return;
}
if (!OPENSSL_G(errors_mark)) {
OPENSSL_G(errors_mark) = pecalloc(1, sizeof(struct php_openssl_errors), 1);
}
memcpy(OPENSSL_G(errors_mark), OPENSSL_G(errors), sizeof(struct php_openssl_errors));
}
/* }}} */
/* {{{ php_openssl_errors_restore_mark */
void php_openssl_errors_restore_mark(void) {
if (!OPENSSL_G(errors)) {
return;
}
struct php_openssl_errors *errors = OPENSSL_G(errors);
if (!OPENSSL_G(errors_mark)) {
errors->top = 0;
errors->bottom = 0;
} else {
memcpy(errors, OPENSSL_G(errors_mark), sizeof(struct php_openssl_errors));
}
}
/* }}} */
/* openssl file path check error function */
static void php_openssl_check_path_error(uint32_t arg_num, int type, const char *format, ...)
{
@@ -1293,6 +1324,7 @@ PHP_GINIT_FUNCTION(openssl)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
openssl_globals->errors = NULL;
openssl_globals->errors_mark = NULL;
}
/* }}} */
@@ -1302,6 +1334,9 @@ PHP_GSHUTDOWN_FUNCTION(openssl)
if (openssl_globals->errors) {
pefree(openssl_globals->errors, 1);
}
if (openssl_globals->errors_mark) {
pefree(openssl_globals->errors_mark, 1);
}
}
/* }}} */
@@ -3571,12 +3606,14 @@ static EVP_PKEY *php_openssl_pkey_from_zval(
}
/* it's an X509 file/cert of some kind, and we need to extract the data from that */
if (public_key) {
php_openssl_errors_set_mark();
cert = php_openssl_x509_from_str(Z_STR_P(val), arg_num, false, NULL);
if (cert) {
free_cert = 1;
} else {
/* not a X509 certificate, try to retrieve public key */
php_openssl_errors_restore_mark();
BIO* in;
if (is_file) {
in = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));

View File

@@ -80,6 +80,7 @@ struct php_openssl_errors {
ZEND_BEGIN_MODULE_GLOBALS(openssl)
struct php_openssl_errors *errors;
struct php_openssl_errors *errors_mark;
ZEND_END_MODULE_GLOBALS(openssl)
#define OPENSSL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(openssl, v)

View File

@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvYH14fT4DPgyffkDOrHt
x0q+rxclB48h2ykgbR3QyDG2d7hMSXjtqEseO/iR1FdAv7UevIKyHFbHpJilOIwo
mEqQNxUQCWdZsWhv7ZVfG8UUgki7LKMGPruJM97vteBS101hSCaCQz+zTyVyP8Uy
nqx5zlPmcBUA92gAFfSCa+tm/lR2BY5g/20mZX/lMY0xXV1iLhfdK6RgJYXX2SdH
YR/01IgmjgTfIp7gX+xixDgGZuZY++jo8C52udFkCf5vxyG4Ed57vRfCLFOPfeY4
r3i0Jiply65zSo8y/6KxudRtmGOfV2qb2EsMTW9PaLs3+rnhhiYBM/nR4V5ux6u6
DwIDAQAB
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,15 @@
--TEST--
Bug #11054: Calling with a PEM public key results in error
--EXTENSIONS--
openssl
--FILE--
<?php
$key_file_name = __DIR__ . '/bug11054.pem';
$key_content = file_get_contents($key_file_name);
openssl_get_publickey($key_content);
var_dump(openssl_error_string());
?>
--EXPECT--
bool(false)

View File

@@ -123,7 +123,7 @@ expect_openssl_errors('openssl_private_decrypt', ['04065072']);
// public encrypt and decrypt with failed padding check and padding
@openssl_public_encrypt("data", $crypted, $public_key_file, 1000);
@openssl_public_decrypt("data", $crypted, $public_key_file);
expect_openssl_errors('openssl_private_(en|de)crypt padding', [$err_pem_no_start_line, '0408F090', '04067072']);
expect_openssl_errors('openssl_private_(en|de)crypt padding', ['0408F090', '04067072']);
// X509
echo "X509 errors\n";

View File

@@ -114,9 +114,6 @@ expect_openssl_errors('openssl_pkey_export_to_file write', ['10080002']);
// successful export
@openssl_pkey_export($private_key_file_with_pass, $out, 'wrong pwd', $options);
expect_openssl_errors('openssl_pkey_export', ['1C800064', '04800065']);
// invalid x509 for getting public key
@openssl_pkey_get_public($private_key_file);
expect_openssl_errors('openssl_pkey_get_public', [$err_pem_no_start_line]);
// private encrypt with unknown padding
@openssl_private_encrypt("data", $crypted, $private_key_file, 1000);
expect_openssl_errors('openssl_private_encrypt', ['1C8000A5']);
@@ -126,7 +123,7 @@ expect_openssl_errors('openssl_private_decrypt', ['0200009F', '02000072']);
// public encrypt and decrypt with failed padding check and padding
@openssl_public_encrypt("data", $crypted, $public_key_file, 1000);
@openssl_public_decrypt("data", $crypted, $public_key_file);
expect_openssl_errors('openssl_private_(en|de)crypt padding', [$err_pem_no_start_line, '02000076', '0200008A', '02000072', '1C880004']);
expect_openssl_errors('openssl_private_(en|de)crypt padding', ['02000076', '0200008A', '02000072', '1C880004']);
// X509
echo "X509 errors\n";
@@ -170,7 +167,6 @@ openssl_pkey_export_to_file opening: ok
openssl_pkey_export_to_file pem: ok
openssl_pkey_export_to_file write: ok
openssl_pkey_export: ok
openssl_pkey_get_public: ok
openssl_private_encrypt: ok
openssl_private_decrypt: ok
openssl_private_(en|de)crypt padding: ok