Skip to content

Commit 4d4b960

Browse files
famoserbukka
authored andcommitted
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
1 parent 5690e8b commit 4d4b960

7 files changed

+66
-6
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ PHP NEWS
118118
- OpenSSL:
119119
. Added OPENSSL_CMS_OLDMIMETYPE and PKCS7_NOOLDMIMETYPE contants to switch
120120
between mime content types. (Daniel Kesselberg)
121+
. Fixed GH-11054: Reset OpenSSL errors when using a PEM public key.
122+
(Florian Moser)
121123

122124
- PCNTL:
123125
. SA_ONSTACK is now set for pcntl_signal. (Kévin Dunglas)

ext/openssl/openssl.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,37 @@ void php_openssl_store_errors(void)
476476
}
477477
/* }}} */
478478

479+
/* {{{ php_openssl_errors_set_mark */
480+
void php_openssl_errors_set_mark(void) {
481+
if (!OPENSSL_G(errors)) {
482+
return;
483+
}
484+
485+
if (!OPENSSL_G(errors_mark)) {
486+
OPENSSL_G(errors_mark) = pecalloc(1, sizeof(struct php_openssl_errors), 1);
487+
}
488+
489+
memcpy(OPENSSL_G(errors_mark), OPENSSL_G(errors), sizeof(struct php_openssl_errors));
490+
}
491+
/* }}} */
492+
493+
/* {{{ php_openssl_errors_restore_mark */
494+
void php_openssl_errors_restore_mark(void) {
495+
if (!OPENSSL_G(errors)) {
496+
return;
497+
}
498+
499+
struct php_openssl_errors *errors = OPENSSL_G(errors);
500+
501+
if (!OPENSSL_G(errors_mark)) {
502+
errors->top = 0;
503+
errors->bottom = 0;
504+
} else {
505+
memcpy(errors, OPENSSL_G(errors_mark), sizeof(struct php_openssl_errors));
506+
}
507+
}
508+
/* }}} */
509+
479510
/* openssl file path check error function */
480511
static void php_openssl_check_path_error(uint32_t arg_num, int type, const char *format, ...)
481512
{
@@ -1293,6 +1324,7 @@ PHP_GINIT_FUNCTION(openssl)
12931324
ZEND_TSRMLS_CACHE_UPDATE();
12941325
#endif
12951326
openssl_globals->errors = NULL;
1327+
openssl_globals->errors_mark = NULL;
12961328
}
12971329
/* }}} */
12981330

@@ -1302,6 +1334,9 @@ PHP_GSHUTDOWN_FUNCTION(openssl)
13021334
if (openssl_globals->errors) {
13031335
pefree(openssl_globals->errors, 1);
13041336
}
1337+
if (openssl_globals->errors_mark) {
1338+
pefree(openssl_globals->errors_mark, 1);
1339+
}
13051340
}
13061341
/* }}} */
13071342

@@ -3571,12 +3606,14 @@ static EVP_PKEY *php_openssl_pkey_from_zval(
35713606
}
35723607
/* it's an X509 file/cert of some kind, and we need to extract the data from that */
35733608
if (public_key) {
3609+
php_openssl_errors_set_mark();
35743610
cert = php_openssl_x509_from_str(Z_STR_P(val), arg_num, false, NULL);
35753611

35763612
if (cert) {
35773613
free_cert = 1;
35783614
} else {
35793615
/* not a X509 certificate, try to retrieve public key */
3616+
php_openssl_errors_restore_mark();
35803617
BIO* in;
35813618
if (is_file) {
35823619
in = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));

ext/openssl/php_openssl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct php_openssl_errors {
8080

8181
ZEND_BEGIN_MODULE_GLOBALS(openssl)
8282
struct php_openssl_errors *errors;
83+
struct php_openssl_errors *errors_mark;
8384
ZEND_END_MODULE_GLOBALS(openssl)
8485

8586
#define OPENSSL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(openssl, v)

ext/openssl/tests/bug11054.pem

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvYH14fT4DPgyffkDOrHt
3+
x0q+rxclB48h2ykgbR3QyDG2d7hMSXjtqEseO/iR1FdAv7UevIKyHFbHpJilOIwo
4+
mEqQNxUQCWdZsWhv7ZVfG8UUgki7LKMGPruJM97vteBS101hSCaCQz+zTyVyP8Uy
5+
nqx5zlPmcBUA92gAFfSCa+tm/lR2BY5g/20mZX/lMY0xXV1iLhfdK6RgJYXX2SdH
6+
YR/01IgmjgTfIp7gX+xixDgGZuZY++jo8C52udFkCf5vxyG4Ed57vRfCLFOPfeY4
7+
r3i0Jiply65zSo8y/6KxudRtmGOfV2qb2EsMTW9PaLs3+rnhhiYBM/nR4V5ux6u6
8+
DwIDAQAB
9+
-----END PUBLIC KEY-----

ext/openssl/tests/bug11054.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
Bug #11054: Calling with a PEM public key results in error
3+
--EXTENSIONS--
4+
openssl
5+
--FILE--
6+
<?php
7+
8+
$key_file_name = __DIR__ . '/bug11054.pem';
9+
$key_content = file_get_contents($key_file_name);
10+
openssl_get_publickey($key_content);
11+
var_dump(openssl_error_string());
12+
13+
?>
14+
--EXPECT--
15+
bool(false)

ext/openssl/tests/openssl_error_string_basic.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ expect_openssl_errors('openssl_private_decrypt', ['04065072']);
123123
// public encrypt and decrypt with failed padding check and padding
124124
@openssl_public_encrypt("data", $crypted, $public_key_file, 1000);
125125
@openssl_public_decrypt("data", $crypted, $public_key_file);
126-
expect_openssl_errors('openssl_private_(en|de)crypt padding', [$err_pem_no_start_line, '0408F090', '04067072']);
126+
expect_openssl_errors('openssl_private_(en|de)crypt padding', ['0408F090', '04067072']);
127127

128128
// X509
129129
echo "X509 errors\n";

ext/openssl/tests/openssl_error_string_basic_openssl3.phpt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,6 @@ expect_openssl_errors('openssl_pkey_export_to_file write', ['10080002']);
114114
// successful export
115115
@openssl_pkey_export($private_key_file_with_pass, $out, 'wrong pwd', $options);
116116
expect_openssl_errors('openssl_pkey_export', ['1C800064', '04800065']);
117-
// invalid x509 for getting public key
118-
@openssl_pkey_get_public($private_key_file);
119-
expect_openssl_errors('openssl_pkey_get_public', [$err_pem_no_start_line]);
120117
// private encrypt with unknown padding
121118
@openssl_private_encrypt("data", $crypted, $private_key_file, 1000);
122119
expect_openssl_errors('openssl_private_encrypt', ['1C8000A5']);
@@ -126,7 +123,7 @@ expect_openssl_errors('openssl_private_decrypt', ['0200009F', '02000072']);
126123
// public encrypt and decrypt with failed padding check and padding
127124
@openssl_public_encrypt("data", $crypted, $public_key_file, 1000);
128125
@openssl_public_decrypt("data", $crypted, $public_key_file);
129-
expect_openssl_errors('openssl_private_(en|de)crypt padding', [$err_pem_no_start_line, '02000076', '0200008A', '02000072', '1C880004']);
126+
expect_openssl_errors('openssl_private_(en|de)crypt padding', ['02000076', '0200008A', '02000072', '1C880004']);
130127

131128
// X509
132129
echo "X509 errors\n";
@@ -170,7 +167,6 @@ openssl_pkey_export_to_file opening: ok
170167
openssl_pkey_export_to_file pem: ok
171168
openssl_pkey_export_to_file write: ok
172169
openssl_pkey_export: ok
173-
openssl_pkey_get_public: ok
174170
openssl_private_encrypt: ok
175171
openssl_private_decrypt: ok
176172
openssl_private_(en|de)crypt padding: ok

0 commit comments

Comments
 (0)