Skip to content

Commit

Permalink
Fix request #70438: Add IV parameter for openssl_seal and openssl_open
Browse files Browse the repository at this point in the history
  • Loading branch information
bukka committed Sep 6, 2015
1 parent a49d394 commit e235cb6
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 31 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ PHP NEWS
. Fixed bug #70001 (Assigning to DOMNode::textContent does additional entity
encoding). (cmb)

- OpenSSL
. Implemented FR #70438 (Add IV parameter for openssl_seal and openssl_open)
(Jakub Zelenka)

- Streams:
. Fixed bug #70361 (HTTP stream wrapper doesn't close keep-alive connections).
(Niklas Keller)
Expand Down
75 changes: 45 additions & 30 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,15 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_seal, 0, 0, 4)
ZEND_ARG_INFO(1, ekeys) /* arary */
ZEND_ARG_INFO(0, pubkeys) /* array */
ZEND_ARG_INFO(0, method)
ZEND_ARG_INFO(1, iv)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(1, opendata)
ZEND_ARG_INFO(0, ekey)
ZEND_ARG_INFO(0, privkey)
ZEND_ARG_INFO(0, iv)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0)
Expand Down Expand Up @@ -4886,20 +4888,21 @@ PHP_FUNCTION(openssl_verify)
Seals data */
PHP_FUNCTION(openssl_seal)
{
zval *pubkeys, *pubkey, *sealdata, *ekeys;
zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL;
HashTable *pubkeysht;
EVP_PKEY **pkeys;
zend_resource ** key_resources; /* so we know what to cleanup */
int i, len1, len2, *eksl, nkeys;
unsigned char *buf = NULL, **eks;
int i, len1, len2, *eksl, nkeys, iv_len;
unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks;
char * data;
size_t data_len;
char *method =NULL;
size_t method_len = 0;
const EVP_CIPHER *cipher;
EVP_CIPHER_CTX ctx;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a/|sz/", &data, &data_len,
&sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) {
return;
}
pubkeysht = HASH_OF(pubkeys);
Expand All @@ -4917,14 +4920,17 @@ PHP_FUNCTION(openssl_seal)
php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
RETURN_FALSE;
}
if (EVP_CIPHER_iv_length(cipher) > 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ciphers with modes requiring IV are not supported");
RETURN_FALSE;
}
} else {
cipher = EVP_rc4();
}

iv_len = EVP_CIPHER_iv_length(cipher);
if (!iv && iv_len > 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Cipher algorithm requires an IV to be supplied as a sixth parameter");
RETURN_FALSE;
}

pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
eks = safe_emalloc(nkeys, sizeof(*eks), 0);
Expand All @@ -4951,16 +4957,12 @@ PHP_FUNCTION(openssl_seal)
goto clean_exit;
}

#if 0
/* Need this if allow ciphers that require initialization vector */
ivlen = EVP_CIPHER_CTX_iv_length(&ctx);
iv = ivlen ? emalloc(ivlen + 1) : NULL;
#endif
/* allocate one byte extra to make room for \0 */
buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
EVP_CIPHER_CTX_cleanup(&ctx);

if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len)) {
if (!EVP_SealInit(&ctx, cipher, eks, eksl, &iv_buf[0], pkeys, nkeys) ||
!EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len)) {
RETVAL_FALSE;
efree(buf);
EVP_CIPHER_CTX_cleanup(&ctx);
Expand All @@ -4983,17 +4985,12 @@ PHP_FUNCTION(openssl_seal)
efree(eks[i]);
eks[i] = NULL;
}
#if 0
/* If allow ciphers that need IV, we need this */
zval_dtor(*ivec);
if (ivlen) {
iv[ivlen] = '\0';
ZVAL_STRINGL(*ivec, iv, ivlen);
efree(iv);
} else {
ZVAL_EMPTY_STRING(*ivec);

if (iv) {
zval_dtor(iv);
iv_buf[iv_len] = '\0';
ZVAL_NEW_STR(iv, zend_string_init((char*)iv_buf, iv_len, 0));
}
#endif
} else {
efree(buf);
}
Expand Down Expand Up @@ -5022,19 +5019,20 @@ PHP_FUNCTION(openssl_open)
{
zval *privkey, *opendata;
EVP_PKEY *pkey;
int len1, len2;
unsigned char *buf;
int len1, len2, cipher_iv_len;
unsigned char *buf, *iv_buf;
zend_resource *keyresource = NULL;
EVP_CIPHER_CTX ctx;
char * data;
size_t data_len;
char * ekey;
size_t ekey_len;
char *method =NULL;
size_t method_len = 0;
char *method = NULL, *iv = NULL;
size_t method_len = 0, iv_len = 0;
const EVP_CIPHER *cipher;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/sz|s", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/sz|ss", &data, &data_len, &opendata,
&ekey, &ekey_len, &privkey, &method, &method_len, &iv, &iv_len) == FAILURE) {
return;
}

Expand All @@ -5057,9 +5055,26 @@ PHP_FUNCTION(openssl_open)
cipher = EVP_rc4();
}

cipher_iv_len = EVP_CIPHER_iv_length(cipher);
if (cipher_iv_len > 0) {
if (!iv) {
php_error_docref(NULL, E_WARNING,
"Cipher algorithm requires an IV to be supplied as a sixth parameter");
RETURN_FALSE;
}
if (cipher_iv_len != iv_len) {
php_error_docref(NULL, E_WARNING, "IV length is invalid");
RETURN_FALSE;
}
iv_buf = (unsigned char *)iv;
} else {
iv_buf = NULL;
}

buf = emalloc(data_len + 1);

if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, (int)ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len)) {
if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) &&
EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len)) {
if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
efree(buf);
RETVAL_FALSE;
Expand Down
2 changes: 1 addition & 1 deletion ext/openssl/tests/bug60632.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ $result = openssl_seal('test phrase', $encrypted, $ekeys, array($pubkey), 'AES-2
echo "Done";
?>
--EXPECTF--
Warning: openssl_seal(): Ciphers with modes requiring IV are not supported in %s on line %d
Warning: openssl_seal(): Cipher algorithm requires an IV to be supplied as a sixth parameter in %s on line %d
Done
29 changes: 29 additions & 0 deletions ext/openssl/tests/bug70438.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Request #70438: Add IV parameter for openssl_seal and openssl_open
--SKIPIF--
<?php
if (!extension_loaded("openssl")) {
print "skip";
}
if (!in_array('AES-128-CBC', openssl_get_cipher_methods(true))) {
print "skip";
}
?>
--FILE--
<?php
$data = "openssl_seal() test";
$cipher = 'AES-128-CBC';
$pub_key = "file://" . dirname(__FILE__) . "/public.key";
$priv_key = "file://" . dirname(__FILE__) . "/private.key";

openssl_seal($data, $sealed, $ekeys, array($pub_key, $pub_key), $cipher);
openssl_seal($data, $sealed, $ekeys, array($pub_key, $pub_key), 'sparkles', $iv);
openssl_seal($data, $sealed, $ekeys, array($pub_key, $pub_key), $cipher, $iv);
openssl_open($sealed, $decrypted, $ekeys[0], $priv_key, $cipher, $iv);
echo $decrypted;
?>
--EXPECTF--
Warning: openssl_seal(): Cipher algorithm requires an IV to be supplied as a sixth parameter in %s on line %d

Warning: openssl_seal(): Unknown signature algorithm. in %s on line %d
openssl_seal() test

0 comments on commit e235cb6

Please sign in to comment.