php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #81724
Patch draw9 revision 2022-07-07 13:02 UTC by nutza249943 at gmail dot com
Patch fix_php_openssl_cms_pkcs7_encrypt revision 2022-07-05 15:25 UTC by johannes dot drummer at power dot cloud

Patch fix_php_openssl_cms_pkcs7_encrypt for OpenSSL related Bug #81724

Patch version 2022-07-05 15:25 UTC

Return to Bug #81724 | Download this patch
This patch is obsolete

Obsoleted by patches:

Patch Revisions:

Developer: johannes.drummer@power.cloud

diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index dd9a891ed8..4ad44ac109 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -5411,6 +5411,36 @@ PHP_FUNCTION(openssl_pkcs7_verify)
 }
 /* }}} */
 
+/** Helper to allow backwards compatibility for functions previously using CONSTANTS */
+const EVP_CIPHER* php_openssl_get_evp_cipher_from_string_or_id(zval * cipher_zval)
+{
+	char * cipher_algo_str = NULL;
+	size_t cipher_algo_str_len = 0;
+	const EVP_CIPHER* cipher = 0;
+	zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
+
+	if (Z_TYPE_P(cipher_zval) == IS_STRING) {
+		cipher_algo_str = Z_STRVAL_P(cipher_zval);
+		cipher_algo_str_len = Z_STRLEN_P(cipher_zval);
+		PHP_OPENSSL_CHECK_SIZE_T_TO_INT_NULL_RETURN(cipher_algo_str_len, cipher_algo_str);
+		cipher = EVP_get_cipherbyname(cipher_algo_str);
+		if (!cipher) {
+			return NULL;
+		}
+	} else {
+		if (Z_TYPE_P(cipher_zval) == IS_LONG) {
+			cipherid = Z_LVAL_P(cipher_zval);
+		}
+		/* sanity check the cipher */
+		cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
+		if (cipher == NULL) {
+			return NULL;
+		}
+	}
+
+	return cipher;
+}
+
 /* {{{ Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
 PHP_FUNCTION(openssl_pkcs7_encrypt)
 {
@@ -5422,7 +5452,7 @@ PHP_FUNCTION(openssl_pkcs7_encrypt)
 	zval * zcertval;
 	X509 * cert;
 	const EVP_CIPHER *cipher = NULL;
-	zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
+	zval * cipher_algo;
 	zend_string * strindex;
 	char * infilename = NULL;
 	size_t infilename_len;
@@ -5431,8 +5461,8 @@ PHP_FUNCTION(openssl_pkcs7_encrypt)
 
 	RETVAL_FALSE;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|ll", &infilename, &infilename_len,
-				&outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|lz", &infilename, &infilename_len,
+				&outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipher_algo) == FAILURE) {
 		RETURN_THROWS();
 	}
 
@@ -5492,10 +5522,8 @@ PHP_FUNCTION(openssl_pkcs7_encrypt)
 		sk_X509_push(recipcerts, cert);
 	}
 
-	/* sanity check the cipher */
-	cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
+	cipher = php_openssl_get_evp_cipher_from_string_or_id(cipher_algo);
 	if (cipher == NULL) {
-		/* shouldn't happen */
 		php_error_docref(NULL, E_WARNING, "Failed to get cipher");
 		goto clean_exit;
 	}
@@ -6018,7 +6046,7 @@ PHP_FUNCTION(openssl_cms_encrypt)
 	zval * zcertval;
 	X509 * cert;
 	const EVP_CIPHER *cipher = NULL;
-	zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
+	zval * cipher_algo = NULL;
 	zend_string * strindex;
 	char * infilename = NULL;
 	size_t infilename_len;
@@ -6028,8 +6056,8 @@ 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) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|llz", &infilename, &infilename_len,
+				  &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &encoding, &cipher_algo) == FAILURE) {
 		RETURN_THROWS();
 	}
 
@@ -6090,10 +6118,8 @@ PHP_FUNCTION(openssl_cms_encrypt)
 		sk_X509_push(recipcerts, cert);
 	}
 
-	/* sanity check the cipher */
-	cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
+	cipher = php_openssl_get_evp_cipher_from_string_or_id(cipher_algo);
 	if (cipher == NULL) {
-		/* shouldn't happen */
 		php_error_docref(NULL, E_WARNING, "Failed to get cipher");
 		goto clean_exit;
 	}
diff --git a/ext/openssl/tests/openssl_cms_decrypt_basic_algo.phpt b/ext/openssl/tests/openssl_cms_decrypt_basic_algo.phpt
new file mode 100644
index 0000000000..0db30e92c7
--- /dev/null
+++ b/ext/openssl/tests/openssl_cms_decrypt_basic_algo.phpt
@@ -0,0 +1,69 @@
+--TEST--
+openssl_cms_decrypt() tests
+--EXTENSIONS--
+openssl
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$encrypted = tempnam(sys_get_temp_dir(), "cms_dec_basic");
+if ($encrypted === false)
+    die("failed to get a temporary filename!");
+$outfile = $encrypted . ".out";
+
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$headers = array("test@test", "testing openssl_cms_encrypt()");
+$wrong = "wrong";
+$empty = "";
+$cipher = "aes-256-gcm";
+
+openssl_cms_encrypt($infile, $encrypted, $single_cert, $headers, cipher_algo: $cipher);
+
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $single_cert, $privkey));
+print("\nDecrypted text:\n");
+readfile($outfile);
+var_dump(openssl_cms_decrypt($encrypted, $outfile, openssl_x509_read($single_cert), $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $single_cert, $wrong));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $wrong, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, null, $privkey));
+var_dump(openssl_cms_decrypt($wrong, $outfile, $single_cert, $privkey));
+var_dump(openssl_cms_decrypt($empty, $outfile, $single_cert, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $empty, $single_cert, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $empty, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $single_cert, $empty));
+
+if (file_exists($encrypted)) {
+    echo "true\n";
+    unlink($encrypted);
+}
+if (file_exists($outfile)) {
+    echo "true\n";
+    unlink($outfile);
+}
+?>
+--EXPECTF--
+bool(true)
+
+Decrypted text:
+Now is the winter of our discontent.
+bool(true)
+
+Warning: openssl_cms_decrypt(): Unable to get private key in %s on line %d
+bool(false)
+
+Warning: openssl_cms_decrypt(): X.509 Certificate cannot be retrieved in %s on line %d
+bool(false)
+
+Warning: openssl_cms_decrypt(): X.509 Certificate cannot be retrieved in %s on line %d
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+
+Warning: openssl_cms_decrypt(): X.509 Certificate cannot be retrieved in %s on line %d
+bool(false)
+
+Warning: openssl_cms_decrypt(): Unable to get private key in %s on line %d
+bool(false)
+true
+true
diff --git a/ext/openssl/tests/openssl_cms_encrypt_basic_algo.phpt b/ext/openssl/tests/openssl_cms_encrypt_basic_algo.phpt
new file mode 100644
index 0000000000..b0e8732b73
--- /dev/null
+++ b/ext/openssl/tests/openssl_cms_encrypt_basic_algo.phpt
@@ -0,0 +1,61 @@
+--TEST--
+openssl_cms_encrypt() tests
+--EXTENSIONS--
+openssl
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$outfile = tempnam(sys_get_temp_dir(), "cms_enc_basic");
+if ($outfile === false)
+    die("failed to get a temporary filename!");
+$outfile2 = $outfile . ".out";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$wrongkey = "file://" . __DIR__ . "/private_rsa_2048.key";
+$multi_certs = array($single_cert, $single_cert);
+$assoc_headers = array("To" => "test@test", "Subject" => "testing openssl_cms_encrypt()");
+$headers = array("test@test", "testing openssl_cms_encrypt()");
+$empty_headers = array();
+$wrong = "wrong";
+$empty = "";
+$cipher = "aes-256-gcm";
+
+var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($infile, $outfile, openssl_x509_read($single_cert), $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_decrypt($outfile, $outfile2, $single_cert, $privkey));
+readfile($outfile2);
+var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $assoc_headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $empty_headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($wrong, $outfile, $single_cert, $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($empty, $outfile, $single_cert, $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($infile, $empty, $single_cert, $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($infile, $outfile, $wrong, $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($infile, $outfile, $empty, $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($infile, $outfile, $multi_certs, $headers, cipher_algo: $cipher));
+var_dump(openssl_cms_encrypt($infile, $outfile, array_map('openssl_x509_read', $multi_certs), $headers, cipher_algo: $cipher));
+
+if (file_exists($outfile)) {
+    echo "true\n";
+    unlink($outfile);
+}
+if (file_exists($outfile2)) {
+    echo "true\n";
+    unlink($outfile2);
+}
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+Now is the winter of our discontent.
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+true
+true
 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Sun Oct 02 12:05:52 2022 UTC