From 20c8c12d9ed83fb06b40e1264a9011913cfea0b9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 11 Aug 2025 21:44:44 +0200 Subject: [PATCH] Fix #81724: openssl_cms_encrypt only allows specific ciphers The allows cipher_algo to be specified as a string. It means the not only predefined ID ciphers are available which means that also auth enveloped data can be created using AES GCM. Closes GH-19459 --- NEWS | 2 ++ UPGRADING | 3 ++ ext/openssl/openssl.c | 22 ++++++++---- ext/openssl/openssl.stub.php | 2 +- ext/openssl/openssl_arginfo.h | 4 +-- .../tests/openssl_cms_encrypt_auth_env.phpt | 34 +++++++++++++++++++ .../tests/openssl_cms_encrypt_basic.phpt | 21 ++++++------ 7 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 ext/openssl/tests/openssl_cms_encrypt_auth_env.phpt diff --git a/NEWS b/NEWS index 6bb6e673f9d..c772d85a2ff 100644 --- a/NEWS +++ b/NEWS @@ -53,6 +53,8 @@ PHP NEWS (Jakub Zelenka) . Implement #47728 (openssl_pkcs7_sign ignores new openssl flags). (Jakub Zelenka) + . Implement #81724 (openssl_cms_encrypt only allows specific ciphers). + (Jakub Zelenka) - PDO: . The "uri:" DSN scheme has been deprecated due to security concerns with diff --git a/UPGRADING b/UPGRADING index 3e41c351958..66c749ea002 100644 --- a/UPGRADING +++ b/UPGRADING @@ -456,6 +456,9 @@ PHP 8.5 UPGRADE NOTES $digest_algo that allows specifying hash digest algorithm for OEAP padding. . openssl_sign() and openssl_verify() have new parameter $padding to allow using more secure RSA PSS padding. + . openssl_cms_encrypt() $cipher_algo parameter can be a string with the + cipher name. That allows to use more algorithms including AES GCM cipher + algorithms for auth enveloped data. - PCNTL: . pcntl_exec() now has a formal return type of false. diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 426898862ea..aefb02a3338 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -3201,6 +3201,7 @@ PHP_FUNCTION(openssl_cms_encrypt) X509 * cert; const EVP_CIPHER *cipher = NULL; zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT; + zend_string *cipher_str = NULL; zend_string * strindex; char * infilename = NULL; size_t infilename_len; @@ -3210,11 +3211,16 @@ PHP_FUNCTION(openssl_cms_encrypt) RETVAL_FALSE; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|lll", &infilename, &infilename_len, - &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &encoding, &cipherid) == FAILURE) { - RETURN_THROWS(); - } - + ZEND_PARSE_PARAMETERS_START(4, 7) + Z_PARAM_PATH(infilename, infilename_len) + Z_PARAM_PATH(outfilename, outfilename_len) + Z_PARAM_ZVAL(zrecipcerts) + Z_PARAM_ARRAY_OR_NULL(zheaders) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(flags) + Z_PARAM_LONG(encoding) + Z_PARAM_STR_OR_LONG(cipher_str, cipherid) + ZEND_PARSE_PARAMETERS_END(); infile = php_openssl_bio_new_file( infilename, infilename_len, 1, PHP_OPENSSL_BIO_MODE_R(flags)); @@ -3273,7 +3279,11 @@ PHP_FUNCTION(openssl_cms_encrypt) } /* sanity check the cipher */ - cipher = php_openssl_get_evp_cipher_from_algo(cipherid); + if (cipher_str) { + cipher = php_openssl_get_evp_cipher_by_name(ZSTR_VAL(cipher_str)); + } else { + cipher = php_openssl_get_evp_cipher_from_algo(cipherid); + } if (cipher == NULL) { /* shouldn't happen */ php_error_docref(NULL, E_WARNING, "Failed to get cipher"); diff --git a/ext/openssl/openssl.stub.php b/ext/openssl/openssl.stub.php index 4950000c775..12cbb0ed618 100644 --- a/ext/openssl/openssl.stub.php +++ b/ext/openssl/openssl.stub.php @@ -574,7 +574,7 @@ function openssl_pkcs7_read(string $data, &$certificates): bool {} function openssl_cms_verify(string $input_filename, int $flags = 0, ?string $certificates = null, array $ca_info = [], ?string $untrusted_certificates_filename = null, ?string $content = null, ?string $pk7 = null, ?string $sigfile = null, int $encoding = OPENSSL_ENCODING_SMIME): bool {} /** @param OpenSSLCertificate|array|string $certificate */ -function openssl_cms_encrypt(string $input_filename, string $output_filename, $certificate, ?array $headers, int $flags = 0, int $encoding = OPENSSL_ENCODING_SMIME, int $cipher_algo = OPENSSL_CIPHER_AES_128_CBC): bool {} +function openssl_cms_encrypt(string $input_filename, string $output_filename, $certificate, ?array $headers, int $flags = 0, int $encoding = OPENSSL_ENCODING_SMIME, string|int $cipher_algo = OPENSSL_CIPHER_AES_128_CBC): bool {} /** * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index c032b7543a3..44415a75892 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 03e511abb97901a4a8268276b809b3cf7afbfa29 */ + * Stub hash: 0e6a5f1a5f23602bafd5b7fdb10525c19a9476fc */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 2, _IS_BOOL, 0) ZEND_ARG_OBJ_TYPE_MASK(0, certificate, OpenSSLCertificate, MAY_BE_STRING, NULL) @@ -219,7 +219,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_cms_encrypt, 0, 4, _IS_B ZEND_ARG_TYPE_INFO(0, headers, IS_ARRAY, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_LONG, 0, "OPENSSL_ENCODING_SMIME") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, cipher_algo, IS_LONG, 0, "OPENSSL_CIPHER_AES_128_CBC") + ZEND_ARG_TYPE_MASK(0, cipher_algo, MAY_BE_STRING|MAY_BE_LONG, "OPENSSL_CIPHER_AES_128_CBC") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_cms_sign, 0, 5, _IS_BOOL, 0) diff --git a/ext/openssl/tests/openssl_cms_encrypt_auth_env.phpt b/ext/openssl/tests/openssl_cms_encrypt_auth_env.phpt new file mode 100644 index 00000000000..9b2086c78ac --- /dev/null +++ b/ext/openssl/tests/openssl_cms_encrypt_auth_env.phpt @@ -0,0 +1,34 @@ +--TEST-- +openssl_cms_encrypt() auth enveloped data tests +--EXTENSIONS-- +openssl +--SKIPIF-- += 3.0'); +?> +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +Now is the winter of our discontent. diff --git a/ext/openssl/tests/openssl_cms_encrypt_basic.phpt b/ext/openssl/tests/openssl_cms_encrypt_basic.phpt index 14b5231fdd3..0ddda76d83a 100644 --- a/ext/openssl/tests/openssl_cms_encrypt_basic.phpt +++ b/ext/openssl/tests/openssl_cms_encrypt_basic.phpt @@ -5,13 +5,9 @@ openssl --FILE-- +--CLEAN-- + --EXPECT-- bool(true) bool(true)