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(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)
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;
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);
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);
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);
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);
}
{
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;
}
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;
--- /dev/null
+--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