Skip to content

Commit cf85cba

Browse files
committed
Add digest algo param to private encrypt and public decrypt
Specifically, it is added to openssl_private_encrypt() and openssl_public_decrypt() functions. The purpose is to specify digest algorithm for OEAP padding. It currently defaults to SHA1 which is not preferred for modern setup and causes problems in compatibility with web crypto.
1 parent 2645663 commit cf85cba

File tree

4 files changed

+79
-11
lines changed

4 files changed

+79
-11
lines changed

ext/openssl/openssl.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3725,6 +3725,29 @@ PHP_FUNCTION(openssl_cms_decrypt)
37253725

37263726
/* }}} */
37273727

3728+
/* Helper to set RSA padding and digest for OAEP */
3729+
static int php_openssl_set_rsa_padding_and_digest(EVP_PKEY_CTX *ctx, zend_long padding, const char *digest_algo)
3730+
{
3731+
if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0) {
3732+
return 0;
3733+
}
3734+
3735+
if (digest_algo != NULL) {
3736+
const EVP_MD *md = php_openssl_get_evp_md_by_name(digest_algo);
3737+
if (md == NULL) {
3738+
php_error_docref(NULL, E_WARNING, "Unknown digest algorithm: %s", digest_algo);
3739+
return 0;
3740+
}
3741+
3742+
if (padding == RSA_PKCS1_OAEP_PADDING) {
3743+
if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0) {
3744+
return 0;
3745+
}
3746+
}
3747+
}
3748+
3749+
return 1;
3750+
}
37283751

37293752
/* {{{ Encrypts data with private key */
37303753
PHP_FUNCTION(openssl_private_encrypt)
@@ -3780,10 +3803,11 @@ PHP_FUNCTION(openssl_private_decrypt)
37803803
{
37813804
zval *key, *crypted;
37823805
zend_long padding = RSA_PKCS1_PADDING;
3783-
char * data;
3784-
size_t data_len;
3806+
char *data;
3807+
char *digest_algo = NULL;
3808+
size_t data_len, digest_algo_len = 0;
37853809

3786-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
3810+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|ls!", &data, &data_len, &crypted, &key, &padding, &digest_algo, &digest_algo_len) == FAILURE) {
37873811
RETURN_THROWS();
37883812
}
37893813

@@ -3798,7 +3822,7 @@ PHP_FUNCTION(openssl_private_decrypt)
37983822
size_t out_len = 0;
37993823
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
38003824
if (!ctx || EVP_PKEY_decrypt_init(ctx) <= 0 ||
3801-
EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
3825+
!php_openssl_set_rsa_padding_and_digest(ctx, padding, digest_algo) ||
38023826
EVP_PKEY_decrypt(ctx, NULL, &out_len, (unsigned char *) data, data_len) <= 0) {
38033827
php_openssl_store_errors();
38043828
RETVAL_FALSE;
@@ -3879,10 +3903,11 @@ PHP_FUNCTION(openssl_public_decrypt)
38793903
{
38803904
zval *key, *crypted;
38813905
zend_long padding = RSA_PKCS1_PADDING;
3882-
char * data;
3883-
size_t data_len;
3906+
char *data;
3907+
char *digest_algo = NULL;
3908+
size_t data_len, digest_algo_len = 0;
38843909

3885-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
3910+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|ls!", &data, &data_len, &crypted, &key, &padding, &digest_algo, &digest_algo_len) == FAILURE) {
38863911
RETURN_THROWS();
38873912
}
38883913

@@ -3897,7 +3922,7 @@ PHP_FUNCTION(openssl_public_decrypt)
38973922
size_t out_len = 0;
38983923
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
38993924
if (!ctx || EVP_PKEY_verify_recover_init(ctx) <= 0 ||
3900-
EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
3925+
!php_openssl_set_rsa_padding_and_digest(ctx, padding, digest_algo) ||
39013926
EVP_PKEY_verify_recover(ctx, NULL, &out_len, (unsigned char *) data, data_len) <= 0) {
39023927
php_openssl_store_errors();
39033928
RETVAL_FALSE;

ext/openssl/openssl.stub.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,13 +575,13 @@ function openssl_private_encrypt(#[\SensitiveParameter] string $data, &$encrypte
575575
* @param string $decrypted_data
576576
* @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key
577577
*/
578-
function openssl_private_decrypt(string $data, #[\SensitiveParameter] &$decrypted_data, #[\SensitiveParameter] $private_key, int $padding = OPENSSL_PKCS1_PADDING): bool {}
578+
function openssl_private_decrypt(string $data, #[\SensitiveParameter] &$decrypted_data, #[\SensitiveParameter] $private_key, int $padding = OPENSSL_PKCS1_PADDING, ?string $digest_algo = null): bool {}
579579

580580
/**
581581
* @param string $encrypted_data
582582
* @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $public_key
583583
*/
584-
function openssl_public_encrypt(#[\SensitiveParameter] string $data, &$encrypted_data, $public_key, int $padding = OPENSSL_PKCS1_PADDING): bool {}
584+
function openssl_public_encrypt(#[\SensitiveParameter] string $data, &$encrypted_data, $public_key, int $padding = OPENSSL_PKCS1_PADDING, ?string $digest_algo = null): bool {}
585585

586586
/**
587587
* @param string $decrypted_data

ext/openssl/openssl_arginfo.h

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
openssl_private_decrypt() with digest algorithm tests
3+
--EXTENSIONS--
4+
openssl
5+
--FILE--
6+
<?php
7+
$data = "Testing openssl_private_decrypt() with digest algorithms";
8+
$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
9+
$pubkey = "file://" . __DIR__ . "/public.key";
10+
11+
openssl_public_encrypt($data, $encrypted_sha256, $pubkey, OPENSSL_PKCS1_OAEP_PADDING, "sha256");
12+
var_dump(openssl_private_decrypt($encrypted_sha256, $output_sha256, $privkey, OPENSSL_PKCS1_OAEP_PADDING, "sha256"));
13+
var_dump($output_sha256);
14+
15+
openssl_public_encrypt($data, $encrypted_default, $pubkey, OPENSSL_PKCS1_OAEP_PADDING);
16+
var_dump(openssl_private_decrypt($encrypted_default, $output_default, $privkey, OPENSSL_PKCS1_OAEP_PADDING));
17+
var_dump($output_default);
18+
19+
var_dump(openssl_private_decrypt($encrypted_sha256, $output_mismatch, $privkey, OPENSSL_PKCS1_OAEP_PADDING, "sha512"));
20+
var_dump($output_mismatch);
21+
22+
var_dump(openssl_private_decrypt($encrypted_sha256, $output_invalid, $privkey, OPENSSL_PKCS1_OAEP_PADDING, "invalid_hash"));
23+
var_dump($output_invalid);
24+
25+
openssl_public_encrypt($data, $encrypted_pkcs1, $pubkey, OPENSSL_PKCS1_PADDING);
26+
var_dump(openssl_private_decrypt($encrypted_pkcs1, $output_pkcs1, $privkey, OPENSSL_PKCS1_PADDING, "sha256"));
27+
var_dump($output_pkcs1);
28+
?>
29+
--EXPECTF--
30+
bool(true)
31+
string(56) "Testing openssl_private_decrypt() with digest algorithms"
32+
bool(true)
33+
string(56) "Testing openssl_private_decrypt() with digest algorithms"
34+
bool(false)
35+
NULL
36+
37+
Warning: openssl_private_decrypt(): Unknown digest algorithm: invalid_hash in %s on line %d
38+
bool(false)
39+
NULL
40+
bool(true)
41+
string(56) "Testing openssl_private_decrypt() with digest algorithms"

0 commit comments

Comments
 (0)