Skip to content

Commit 20c8c12

Browse files
committed
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
1 parent 38beb44 commit 20c8c12

File tree

7 files changed

+68
-20
lines changed

7 files changed

+68
-20
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ PHP NEWS
5353
(Jakub Zelenka)
5454
. Implement #47728 (openssl_pkcs7_sign ignores new openssl flags).
5555
(Jakub Zelenka)
56+
. Implement #81724 (openssl_cms_encrypt only allows specific ciphers).
57+
(Jakub Zelenka)
5658

5759
- PDO:
5860
. The "uri:" DSN scheme has been deprecated due to security concerns with

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,9 @@ PHP 8.5 UPGRADE NOTES
456456
$digest_algo that allows specifying hash digest algorithm for OEAP padding.
457457
. openssl_sign() and openssl_verify() have new parameter $padding to allow
458458
using more secure RSA PSS padding.
459+
. openssl_cms_encrypt() $cipher_algo parameter can be a string with the
460+
cipher name. That allows to use more algorithms including AES GCM cipher
461+
algorithms for auth enveloped data.
459462

460463
- PCNTL:
461464
. pcntl_exec() now has a formal return type of false.

ext/openssl/openssl.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3201,6 +3201,7 @@ PHP_FUNCTION(openssl_cms_encrypt)
32013201
X509 * cert;
32023202
const EVP_CIPHER *cipher = NULL;
32033203
zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
3204+
zend_string *cipher_str = NULL;
32043205
zend_string * strindex;
32053206
char * infilename = NULL;
32063207
size_t infilename_len;
@@ -3210,11 +3211,16 @@ PHP_FUNCTION(openssl_cms_encrypt)
32103211

32113212
RETVAL_FALSE;
32123213

3213-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|lll", &infilename, &infilename_len,
3214-
&outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &encoding, &cipherid) == FAILURE) {
3215-
RETURN_THROWS();
3216-
}
3217-
3214+
ZEND_PARSE_PARAMETERS_START(4, 7)
3215+
Z_PARAM_PATH(infilename, infilename_len)
3216+
Z_PARAM_PATH(outfilename, outfilename_len)
3217+
Z_PARAM_ZVAL(zrecipcerts)
3218+
Z_PARAM_ARRAY_OR_NULL(zheaders)
3219+
Z_PARAM_OPTIONAL
3220+
Z_PARAM_LONG(flags)
3221+
Z_PARAM_LONG(encoding)
3222+
Z_PARAM_STR_OR_LONG(cipher_str, cipherid)
3223+
ZEND_PARSE_PARAMETERS_END();
32183224

32193225
infile = php_openssl_bio_new_file(
32203226
infilename, infilename_len, 1, PHP_OPENSSL_BIO_MODE_R(flags));
@@ -3273,7 +3279,11 @@ PHP_FUNCTION(openssl_cms_encrypt)
32733279
}
32743280

32753281
/* sanity check the cipher */
3276-
cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
3282+
if (cipher_str) {
3283+
cipher = php_openssl_get_evp_cipher_by_name(ZSTR_VAL(cipher_str));
3284+
} else {
3285+
cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
3286+
}
32773287
if (cipher == NULL) {
32783288
/* shouldn't happen */
32793289
php_error_docref(NULL, E_WARNING, "Failed to get cipher");

ext/openssl/openssl.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ function openssl_pkcs7_read(string $data, &$certificates): bool {}
574574
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 {}
575575

576576
/** @param OpenSSLCertificate|array|string $certificate */
577-
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 {}
577+
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 {}
578578

579579
/**
580580
* @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key

ext/openssl/openssl_arginfo.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
openssl_cms_encrypt() auth enveloped data tests
3+
--EXTENSIONS--
4+
openssl
5+
--SKIPIF--
6+
<?php
7+
if (OPENSSL_VERSION_NUMBER < 0x30000000) die('skip For OpenSSL >= 3.0');
8+
?>
9+
--FILE--
10+
<?php
11+
$infile = __DIR__ . "/plain.txt";
12+
$outfile = __DIR__ . "/openssl_cms_encrypt_auth_env.out1";
13+
$outfile2 = __DIR__ . "/openssl_cms_encrypt_auth_env.out2";
14+
$single_cert = "file://" . __DIR__ . "/cert.crt";
15+
$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
16+
$headers = array("test@test", "testing openssl_cms_encrypt()");
17+
$cipher = "AES-128-GCM";
18+
19+
var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $headers, cipher_algo: $cipher));
20+
var_dump(openssl_cms_encrypt($infile, $outfile, openssl_x509_read($single_cert), $headers, cipher_algo: $cipher));
21+
var_dump(openssl_cms_decrypt($outfile, $outfile2, $single_cert, $privkey));
22+
readfile($outfile2);
23+
24+
?>
25+
--CLEAN--
26+
<?php
27+
@unlink(__DIR__ . "/openssl_cms_encrypt_auth_env.out1");
28+
@unlink(__DIR__ . "/openssl_cms_encrypt_auth_env.out2");
29+
?>
30+
--EXPECT--
31+
bool(true)
32+
bool(true)
33+
bool(true)
34+
Now is the winter of our discontent.

ext/openssl/tests/openssl_cms_encrypt_basic.phpt

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@ openssl
55
--FILE--
66
<?php
77
$infile = __DIR__ . "/plain.txt";
8-
$outfile = tempnam(sys_get_temp_dir(), "cms_enc_basic");
9-
if ($outfile === false)
10-
die("failed to get a temporary filename!");
11-
$outfile2 = $outfile . ".out";
12-
$outfile3 = tempnam(sys_get_temp_dir(), "cms_enc_basic");
13-
if ($outfile3 === false)
14-
die("failed to get a temporary filename!");
8+
$outfile = __DIR__ . "/openssl_cms_encrypt_basic.out1";
9+
$outfile2 = __DIR__ . "/openssl_cms_encrypt_basic.out2";
10+
$outfile3 = __DIR__ . "/openssl_cms_encrypt_basic.out3";
1511
$single_cert = "file://" . __DIR__ . "/cert.crt";
1612
$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
1713
$wrongkey = "file://" . __DIR__ . "/private_rsa_2048.key";
@@ -27,7 +23,7 @@ var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $headers, cipher_a
2723
var_dump(openssl_cms_encrypt($infile, $outfile, openssl_x509_read($single_cert), $headers, cipher_algo: $cipher));
2824
var_dump(openssl_cms_decrypt($outfile, $outfile2, $single_cert, $privkey));
2925
readfile($outfile2);
30-
var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $assoc_headers, cipher_algo: $cipher));
26+
var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $assoc_headers, cipher_algo: "AES-128-CBC"));
3127
var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $empty_headers, cipher_algo: $cipher));
3228
var_dump(openssl_cms_encrypt($wrong, $outfile, $single_cert, $headers, cipher_algo: $cipher));
3329
var_dump(openssl_cms_encrypt($empty, $outfile, $single_cert, $headers, cipher_algo: $cipher));
@@ -40,11 +36,9 @@ var_dump(openssl_cms_encrypt($infile, $outfile3, $single_cert, $headers, flags:
4036

4137
if (file_exists($outfile)) {
4238
echo "true\n";
43-
unlink($outfile);
4439
}
4540
if (file_exists($outfile2)) {
4641
echo "true\n";
47-
unlink($outfile2);
4842
}
4943

5044
if (file_exists($outfile3)) {
@@ -53,9 +47,14 @@ if (file_exists($outfile3)) {
5347
echo "true\n";
5448
}
5549
unset($content);
56-
unlink($outfile3);
5750
}
5851
?>
52+
--CLEAN--
53+
<?php
54+
@unlink(__DIR__ . "/openssl_cms_encrypt_basic.out1");
55+
@unlink(__DIR__ . "/openssl_cms_encrypt_basic.out2");
56+
@unlink(__DIR__ . "/openssl_cms_encrypt_basic.out3");
57+
?>
5958
--EXPECT--
6059
bool(true)
6160
bool(true)

0 commit comments

Comments
 (0)