php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login

Patch bug60632_new_parameter_for_iv_ciphers.patch for OpenSSL related Bug #60632

Patch version 2013-11-10 21:18 UTC

Return to Bug #60632 | Download this patch
Patch Revisions:

Developer: jorrit@wafel.org

diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 7cf637c..24002b9 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -348,6 +348,8 @@ ZEND_BEGIN_ARG_INFO(arginfo_openssl_seal, 0)
     ZEND_ARG_INFO(1, sealdata)
     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)
@@ -355,6 +357,8 @@ 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, method) 
+    ZEND_ARG_INFO(0, iv) 
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0)
@@ -4731,19 +4735,21 @@ PHP_FUNCTION(openssl_verify)
 PHP_FUNCTION(openssl_seal)
 {
 	zval *pubkeys, **pubkey, *sealdata, *ekeys;
+	zval *iv = NULL;
 	HashTable *pubkeysht;
 	HashPosition pos;
 	EVP_PKEY **pkeys;
 	long * key_resources;	/* so we know what to cleanup */
-	int i, len1, len2, *eksl, nkeys;
+	int i, len1, len2, *eksl, nkeys, max_iv_len;
 	unsigned char *buf = NULL, **eks;
 	char * data; int data_len;
 	char *method =NULL;
+	unsigned char *ivbuf = NULL;
 	int method_len = 0;
 	const EVP_CIPHER *cipher;
 	EVP_CIPHER_CTX ctx;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|sz/", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) {
 		return;
 	}
 	
@@ -4764,6 +4770,17 @@ PHP_FUNCTION(openssl_seal)
 		cipher = EVP_rc4();
 	}
 
+	max_iv_len = EVP_CIPHER_iv_length(cipher);
+
+	if (max_iv_len > 0) {
+		if (iv == NULL) { 
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cipher uses an IV that must be returned, while no IV parameter is specified.");
+			RETURN_FALSE;
+		}
+
+		ivbuf = emalloc(max_iv_len + 1);
+	}
+
 	pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
 	eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
 	eks = safe_emalloc(nkeys, sizeof(*eks), 0);
@@ -4792,15 +4809,10 @@ 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));
 
-	if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
+	if (!EVP_SealInit(&ctx, cipher, eks, eksl, ivbuf, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
 		RETVAL_FALSE;
 		efree(buf);
 		goto clean_exit;
@@ -4821,16 +4833,18 @@ PHP_FUNCTION(openssl_seal)
 			add_next_index_stringl(ekeys, erealloc(eks[i], eksl[i] + 1), eksl[i], 0);
 			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, erealloc(iv, ivlen + 1), ivlen, 0);
-		} else {
-			ZVAL_EMPTY_STRING(*ivec);
+
+		if (iv) {
+			zval_dtor(iv);
+
+			if (max_iv_len > 0) {
+				ivbuf[max_iv_len] = '\0';
+				ZVAL_STRINGL(iv, (char *)ivbuf, max_iv_len, 0);
+				ivbuf = NULL;
+			} else {
+				ZVAL_EMPTY_STRING(iv);
+			}
 		}
-#endif
 	} else {
 		efree(buf);
 	}
@@ -4845,6 +4859,10 @@ clean_exit:
 			efree(eks[i]);
 		}
 	}
+
+	if (ivbuf) {
+		efree(ivbuf);
+	}
 	efree(eks);
 	efree(eksl);
 	efree(pkeys);
@@ -4866,9 +4884,11 @@ PHP_FUNCTION(openssl_open)
 	char * ekey;	int ekey_len;
 	char *method =NULL;
 	int method_len = 0;
+	char *iv = NULL;
+	int iv_len, max_iv_len;
 	const EVP_CIPHER *cipher;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ|s", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ|ss", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len, &iv, &iv_len) == FAILURE) {
 		return;
 	}
 
@@ -4888,9 +4908,24 @@ PHP_FUNCTION(openssl_open)
 		cipher = EVP_rc4();
 	}
 	
+	max_iv_len = EVP_CIPHER_iv_length(cipher);
+
+	if (max_iv_len > 0) {
+		if (iv == NULL) { 
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cipher requires an IV, while no IV parameter is specified.");
+			RETURN_FALSE;
+		}
+		if (iv_len != max_iv_len) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IV length.");
+			RETURN_FALSE;
+		}
+	} else {
+		iv = NULL;
+	}
+
 	buf = emalloc(data_len + 1);
 
-	if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
+	if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, iv, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
 		if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
 			efree(buf);
 			if (keyresource == -1) { 
diff --git a/ext/openssl/tests/bug60632.phpt b/ext/openssl/tests/bug60632.phpt
index e69de29..63a8d86 100644
--- a/ext/openssl/tests/bug60632.phpt
+++ b/ext/openssl/tests/bug60632.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #60632: openssl_seal fails with AES
+--SKIPIF--
+<?php 
+if (!extension_loaded("openssl")) print "skip"; 
+if (!in_array('AES128', openssl_get_cipher_methods(true))) print "skip";
+?>
+--FILE--
+<?php
+$data = "openssl_seal() test";
+$cipher = 'AES128';
+$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 uses an IV that must be returned, while no IV parameter is specified. in %s on line %d
+
+Warning: openssl_seal(): Unknown signature algorithm. in %s on line %d
+openssl_seal() test
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 08:01:32 2024 UTC