]> granicus.if.org Git - php/commitdiff
Fix request #70438: Add IV parameter for openssl_seal and openssl_open
authorJakub Zelenka <bukka@php.net>
Sun, 6 Sep 2015 18:09:56 +0000 (19:09 +0100)
committerJakub Zelenka <bukka@php.net>
Sun, 6 Sep 2015 18:09:56 +0000 (19:09 +0100)
NEWS
ext/openssl/openssl.c
ext/openssl/tests/bug60632.phpt
ext/openssl/tests/bug70438.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 82bf2fed400af8ce17925d893d58f1a30efd3b60..81a91173fa791caa8c99852a412f18dc4a964230 100644 (file)
--- 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)
index 4ec4c4f4ed2b99f3ad35c00806082b524e041236..7d3a3f03daab110286aba9da40e6eb8fd1ebb01d 100644 (file)
@@ -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;
index c718fed6dbad925d8fcffecabbd0d7a89d5f761b..972c20e3b8d1066b0fb7b6e69f21aaa86c6c7213 100644 (file)
@@ -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 (file)
index 0000000..de87a51
--- /dev/null
@@ -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