summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Zelenka <bukka@php.net>2015-09-06 19:09:56 +0100
committerJakub Zelenka <bukka@php.net>2015-09-06 19:09:56 +0100
commite235cb65fbb2b16eb6ee35c0786d9f42f1a74e2c (patch)
tree7a2d022ad0673bbe25cf71554c5f8b7f4af1dfd5
parenta49d394beb80cf0efa582559463af9a045fc0407 (diff)
downloadphp-git-e235cb65fbb2b16eb6ee35c0786d9f42f1a74e2c.tar.gz
Fix request #70438: Add IV parameter for openssl_seal and openssl_open
-rw-r--r--NEWS4
-rw-r--r--ext/openssl/openssl.c75
-rw-r--r--ext/openssl/tests/bug60632.phpt2
-rw-r--r--ext/openssl/tests/bug70438.phpt29
4 files changed, 79 insertions, 31 deletions
diff --git a/NEWS b/NEWS
index 82bf2fed40..81a91173fa 100644
--- a/NEWS
+++ b/NEWS
@@ -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)
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 4ec4c4f4ed..7d3a3f03da 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -358,6 +358,7 @@ 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)
@@ -365,6 +366,7 @@ ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0)
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)
@@ -4886,12 +4888,12 @@ 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;
@@ -4899,7 +4901,8 @@ PHP_FUNCTION(openssl_seal)
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);
@@ -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);
@@ -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);
@@ -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);
}
@@ -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;
}
@@ -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;
diff --git a/ext/openssl/tests/bug60632.phpt b/ext/openssl/tests/bug60632.phpt
index c718fed6db..972c20e3b8 100644
--- a/ext/openssl/tests/bug60632.phpt
+++ b/ext/openssl/tests/bug60632.phpt
@@ -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
diff --git a/ext/openssl/tests/bug70438.phpt b/ext/openssl/tests/bug70438.phpt
new file mode 100644
index 0000000000..de87a51a7a
--- /dev/null
+++ b/ext/openssl/tests/bug70438.phpt
@@ -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