Skip to content

Commit 108c57a

Browse files
committed
Add digest algo param to public encrypt and private decrypt
Specifically, it is added to openssl_public_encrypt() and openssl_private_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. Closes phpGH-19223
1 parent 2645663 commit 108c57a

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;
@@ -3831,9 +3855,10 @@ PHP_FUNCTION(openssl_public_encrypt)
38313855
zval *key, *crypted;
38323856
zend_long padding = RSA_PKCS1_PADDING;
38333857
char * data;
3834-
size_t data_len;
3858+
char *digest_algo = NULL;
3859+
size_t data_len, digest_algo_len = 0;
38353860

3836-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
3861+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|ls!", &data, &data_len, &crypted, &key, &padding, &digest_algo, &digest_algo_len) == FAILURE) {
38373862
RETURN_THROWS();
38383863
}
38393864

@@ -3848,7 +3873,7 @@ PHP_FUNCTION(openssl_public_encrypt)
38483873
size_t out_len = 0;
38493874
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
38503875
if (!ctx || EVP_PKEY_encrypt_init(ctx) <= 0 ||
3851-
EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
3876+
!php_openssl_set_rsa_padding_and_digest(ctx, padding, digest_algo) ||
38523877
EVP_PKEY_encrypt(ctx, NULL, &out_len, (unsigned char *) data, data_len) <= 0) {
38533878
php_openssl_store_errors();
38543879
RETVAL_FALSE;
@@ -3879,7 +3904,7 @@ PHP_FUNCTION(openssl_public_decrypt)
38793904
{
38803905
zval *key, *crypted;
38813906
zend_long padding = RSA_PKCS1_PADDING;
3882-
char * data;
3907+
char *data;
38833908
size_t data_len;
38843909

38853910
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {

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)