Skip to content

Commit

Permalink
Use EVP_PKEY API for openssl_public_encrypt/private_decrypt
Browse files Browse the repository at this point in the history
Use the high level API instead of the deprecated low level API.
  • Loading branch information
nikic committed Aug 4, 2021
1 parent 503146a commit 0233afa
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 74 deletions.
117 changes: 44 additions & 73 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -6197,11 +6197,6 @@ PHP_FUNCTION(openssl_private_encrypt)
PHP_FUNCTION(openssl_private_decrypt)
{
zval *key, *crypted;
EVP_PKEY *pkey;
int cryptedlen;
zend_string *cryptedbuf = NULL;
unsigned char *crypttemp;
int successful = 0;
zend_long padding = RSA_PKCS1_PADDING;
char * data;
size_t data_len;
Expand All @@ -6210,65 +6205,48 @@ PHP_FUNCTION(openssl_private_decrypt)
RETURN_THROWS();
}

PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data, 1);

RETVAL_FALSE;

pkey = php_openssl_pkey_from_zval(key, 0, "", 0);
EVP_PKEY *pkey = php_openssl_pkey_from_zval(key, 0, "", 0);
if (pkey == NULL) {
if (!EG(exception)) {
php_error_docref(NULL, E_WARNING, "key parameter is not a valid private key");
}
RETURN_FALSE;
}

cryptedlen = EVP_PKEY_size(pkey);
crypttemp = emalloc(cryptedlen + 1);

switch (EVP_PKEY_id(pkey)) {
case EVP_PKEY_RSA:
case EVP_PKEY_RSA2:
cryptedlen = RSA_private_decrypt((int)data_len,
(unsigned char *)data,
crypttemp,
EVP_PKEY_get0_RSA(pkey),
(int)padding);
if (cryptedlen != -1) {
cryptedbuf = zend_string_alloc(cryptedlen, 0);
memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen);
successful = 1;
}
break;
default:
php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
size_t out_len = 0;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!ctx || EVP_PKEY_decrypt_init(ctx) <= 0 ||
EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
EVP_PKEY_decrypt(ctx, NULL, &out_len, (unsigned char *) data, data_len) <= 0) {
php_openssl_store_errors();
RETVAL_FALSE;
goto cleanup;
}

efree(crypttemp);

if (successful) {
ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
ZEND_TRY_ASSIGN_REF_NEW_STR(crypted, cryptedbuf);
cryptedbuf = NULL;
RETVAL_TRUE;
} else {
zend_string *out = zend_string_alloc(out_len, 0);
if (EVP_PKEY_decrypt(ctx, (unsigned char *) ZSTR_VAL(out), &out_len,
(unsigned char *) data, data_len) <= 0) {
zend_string_release(out);
php_openssl_store_errors();
RETVAL_FALSE;
goto cleanup;
}

out = zend_string_truncate(out, out_len, 0);
ZSTR_VAL(out)[out_len] = '\0';
ZEND_TRY_ASSIGN_REF_NEW_STR(crypted, out);
RETVAL_TRUE;

cleanup:
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
if (cryptedbuf) {
zend_string_release_ex(cryptedbuf, 0);
}
}
/* }}} */

/* {{{ Encrypts data with public key */
PHP_FUNCTION(openssl_public_encrypt)
{
zval *key, *crypted;
EVP_PKEY *pkey;
int cryptedlen;
zend_string *cryptedbuf;
int successful = 0;
zend_long padding = RSA_PKCS1_PADDING;
char * data;
size_t data_len;
Expand All @@ -6277,47 +6255,40 @@ PHP_FUNCTION(openssl_public_encrypt)
RETURN_THROWS();
}

PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data, 1);

RETVAL_FALSE;

pkey = php_openssl_pkey_from_zval(key, 1, NULL, 0);
EVP_PKEY *pkey = php_openssl_pkey_from_zval(key, 1, NULL, 0);
if (pkey == NULL) {
if (!EG(exception)) {
php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key");
}
RETURN_FALSE;
}

cryptedlen = EVP_PKEY_size(pkey);
cryptedbuf = zend_string_alloc(cryptedlen, 0);

switch (EVP_PKEY_id(pkey)) {
case EVP_PKEY_RSA:
case EVP_PKEY_RSA2:
successful = (RSA_public_encrypt((int)data_len,
(unsigned char *)data,
(unsigned char *)ZSTR_VAL(cryptedbuf),
EVP_PKEY_get0_RSA(pkey),
(int)padding) == cryptedlen);
break;
default:
php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");

size_t out_len = 0;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!ctx || EVP_PKEY_encrypt_init(ctx) <= 0 ||
EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
EVP_PKEY_encrypt(ctx, NULL, &out_len, (unsigned char *) data, data_len) <= 0) {
php_openssl_store_errors();
RETVAL_FALSE;
goto cleanup;
}

if (successful) {
ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
ZEND_TRY_ASSIGN_REF_NEW_STR(crypted, cryptedbuf);
cryptedbuf = NULL;
RETVAL_TRUE;
} else {
zend_string *out = zend_string_alloc(out_len, 0);
if (EVP_PKEY_encrypt(ctx, (unsigned char *) ZSTR_VAL(out), &out_len,
(unsigned char *) data, data_len) <= 0) {
zend_string_release(out);
php_openssl_store_errors();
RETVAL_FALSE;
goto cleanup;
}

ZSTR_VAL(out)[out_len] = '\0';
ZEND_TRY_ASSIGN_REF_NEW_STR(crypted, out);
RETVAL_TRUE;

cleanup:
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
if (cryptedbuf) {
zend_string_release_ex(cryptedbuf, 0);
}
}
/* }}} */

Expand Down
2 changes: 1 addition & 1 deletion ext/openssl/tests/openssl_error_string_basic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ expect_openssl_errors('openssl_private_decrypt', ['04065072']);
// public encrypt and decrypt with failed padding check and padding
@openssl_public_encrypt("data", $crypted, $public_key_file, 1000);
@openssl_public_decrypt("data", $crypted, $public_key_file);
expect_openssl_errors('openssl_private_(en|de)crypt padding', [$err_pem_no_start_line, '04068076', '04067072']);
expect_openssl_errors('openssl_private_(en|de)crypt padding', [$err_pem_no_start_line, '0408F090', '04067072']);

// X509
echo "X509 errors\n";
Expand Down

0 comments on commit 0233afa

Please sign in to comment.