diff --git a/NEWS b/NEWS index b0994af905a..3b5b6f03c88 100644 --- a/NEWS +++ b/NEWS @@ -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) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index f74f25c3040..4009a5b84df 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -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)); diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 5cfadbedc98..304854b4bf9 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -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) diff --git a/ext/openssl/tests/bug11054.pem b/ext/openssl/tests/bug11054.pem new file mode 100644 index 00000000000..60d7afa827f --- /dev/null +++ b/ext/openssl/tests/bug11054.pem @@ -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----- diff --git a/ext/openssl/tests/bug11054.phpt b/ext/openssl/tests/bug11054.phpt new file mode 100644 index 00000000000..25f23d5b1de --- /dev/null +++ b/ext/openssl/tests/bug11054.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #11054: Calling with a PEM public key results in error +--EXTENSIONS-- +openssl +--FILE-- + +--EXPECT-- +bool(false) diff --git a/ext/openssl/tests/openssl_error_string_basic.phpt b/ext/openssl/tests/openssl_error_string_basic.phpt index e4ea264b3bf..02e8b3fbc49 100644 --- a/ext/openssl/tests/openssl_error_string_basic.phpt +++ b/ext/openssl/tests/openssl_error_string_basic.phpt @@ -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"; diff --git a/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt b/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt index d435a53e304..041a0a0b564 100644 --- a/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt +++ b/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt @@ -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