summaryrefslogtreecommitdiff
path: root/ext/openssl
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2010-10-21 08:52:46 +0200
committerOndřej Surý <ondrej@sury.org>2010-10-21 08:52:46 +0200
commit01fcdff3849c3691d9aaeaab735846ab6d8895ca (patch)
tree6460876d356113fa7053df36f2aa00baa7db24a9 /ext/openssl
parent855a09f4eded707941180c9d90acd17c25e29447 (diff)
downloadphp-01fcdff3849c3691d9aaeaab735846ab6d8895ca.tar.gz
Imported Upstream version 5.3.3upstream/5.3.3
Diffstat (limited to 'ext/openssl')
-rw-r--r--ext/openssl/openssl.c170
-rw-r--r--ext/openssl/tests/011.phpt13
-rw-r--r--ext/openssl/tests/bug48182.phpt2
-rw-r--r--ext/openssl/tests/openssl_decrypt_error.phpt7
-rw-r--r--ext/openssl/xp_ssl.c15
5 files changed, 155 insertions, 52 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 8df0d9d69..af968c83f 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -20,7 +20,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: openssl.c 294508 2010-02-04 09:23:22Z pajoye $ */
+/* $Id: openssl.c 300764 2010-06-26 16:03:39Z felipe $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -99,6 +99,7 @@ PHP_FUNCTION(openssl_get_cipher_methods);
PHP_FUNCTION(openssl_digest);
PHP_FUNCTION(openssl_encrypt);
PHP_FUNCTION(openssl_decrypt);
+PHP_FUNCTION(openssl_cipher_iv_length);
PHP_FUNCTION(openssl_dh_compute_key);
PHP_FUNCTION(openssl_random_pseudo_bytes);
@@ -347,6 +348,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, 3)
ZEND_ARG_INFO(0, method)
ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, raw_output)
+ ZEND_ARG_INFO(0, iv)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
@@ -354,6 +356,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
ZEND_ARG_INFO(0, method)
ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, raw_input)
+ ZEND_ARG_INFO(0, iv)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_openssl_cipher_iv_length, 0)
+ ZEND_ARG_INFO(0, method)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0)
@@ -379,9 +386,9 @@ const zend_function_entry openssl_functions[] = {
PHP_FE(openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
PHP_FE(openssl_pkey_get_details, arginfo_openssl_pkey_get_details)
- PHP_FALIAS(openssl_free_key, openssl_pkey_free, NULL)
- PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, NULL)
- PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, NULL)
+ PHP_FALIAS(openssl_free_key, openssl_pkey_free, arginfo_openssl_pkey_free)
+ PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
+ PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
/* x.509 cert funcs */
PHP_FE(openssl_x509_read, arginfo_openssl_x509_read)
@@ -408,6 +415,7 @@ const zend_function_entry openssl_functions[] = {
PHP_FE(openssl_digest, arginfo_openssl_digest)
PHP_FE(openssl_encrypt, arginfo_openssl_encrypt)
PHP_FE(openssl_decrypt, arginfo_openssl_decrypt)
+ PHP_FE(openssl_cipher_iv_length, arginfo_openssl_cipher_iv_length)
PHP_FE(openssl_sign, arginfo_openssl_sign)
PHP_FE(openssl_verify, arginfo_openssl_verify)
PHP_FE(openssl_seal, arginfo_openssl_seal)
@@ -4435,7 +4443,9 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
if (!cipherlist) {
cipherlist = "DEFAULT";
}
- SSL_CTX_set_cipher_list(ctx, cipherlist);
+ if (SSL_CTX_set_cipher_list(ctx, cipherlist) != 1) {
+ return NULL;
+ }
GET_VER_OPT_STRING("local_cert", certfile);
if (certfile) {
@@ -4443,6 +4453,7 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
EVP_PKEY *key = NULL;
SSL *tmpssl;
char resolved_path_buff[MAXPATHLEN];
+ const char * private_key = NULL;
if (VCWD_REALPATH(certfile, resolved_path_buff)) {
/* a certificate to use for authentication */
@@ -4450,10 +4461,21 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set local cert chain file `%s'; Check that your cafile/capath settings include details of your certificate and its issuer", certfile);
return NULL;
}
-
- if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff);
- return NULL;
+ GET_VER_OPT_STRING("local_pk", private_key);
+
+ if (private_key) {
+ char resolved_path_buff_pk[MAXPATHLEN];
+ if (VCWD_REALPATH(private_key, resolved_path_buff_pk)) {
+ if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff_pk, SSL_FILETYPE_PEM) != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff_pk);
+ return NULL;
+ }
+ }
+ } else {
+ if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff);
+ return NULL;
+ }
}
tmpssl = SSL_new(ctx);
@@ -4576,19 +4598,54 @@ PHP_FUNCTION(openssl_digest)
}
/* }}} */
-/* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false])
+static zend_bool php_openssl_validate_iv(char **piv, int *piv_len, int iv_required_len TSRMLS_DC)
+{
+ char *iv_new;
+
+ /* Best case scenario, user behaved */
+ if (*piv_len == iv_required_len) {
+ return 0;
+ }
+
+ iv_new = ecalloc(1, iv_required_len + 1);
+
+ if (*piv_len <= 0) {
+ /* BC behavior */
+ *piv_len = iv_required_len;
+ *piv = iv_new;
+ return 1;
+ }
+
+ if (*piv_len < iv_required_len) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "IV passed is only %d bytes long, cipher expects an IV of precisely %d bytes, padding with \\0", *piv_len, iv_required_len);
+ memcpy(iv_new, *piv, *piv_len);
+ *piv_len = iv_required_len;
+ *piv = iv_new;
+ return 1;
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "IV passed is %d bytes long which is longer than the %d expected by selected cipher, truncating", *piv_len, iv_required_len);
+ memcpy(iv_new, *piv, iv_required_len);
+ *piv_len = iv_required_len;
+ *piv = iv_new;
+ return 1;
+
+}
+
+/* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false [, string $iv='']])
Encrypts given data with given method and key, returns raw or base64 encoded string */
PHP_FUNCTION(openssl_encrypt)
{
zend_bool raw_output = 0;
- char *data, *method, *password;
- int data_len, method_len, password_len;
+ char *data, *method, *password, *iv = "";
+ int data_len, method_len, password_len, iv_len = 0;
const EVP_CIPHER *cipher_type;
EVP_CIPHER_CTX cipher_ctx;
- int i, outlen, keylen, ivlen;
- unsigned char *outbuf, *key, *iv;
+ int i, outlen, keylen;
+ unsigned char *outbuf, *key;
+ zend_bool free_iv;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, &data_len, &method, &method_len, &password, &password_len, &raw_output) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|bs", &data, &data_len, &method, &method_len, &password, &password_len, &raw_output, &iv, &iv_len) == FAILURE) {
return;
}
cipher_type = EVP_get_cipherbyname(method);
@@ -4606,14 +4663,15 @@ PHP_FUNCTION(openssl_encrypt)
key = (unsigned char*)password;
}
- ivlen = EVP_CIPHER_iv_length(cipher_type);
- iv = emalloc(ivlen);
- memset(iv, 0, ivlen);
+ if (iv_len <= 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Using an empty Initialization Vector (iv) is potentially insecure and not recommended");
+ }
+ free_iv = php_openssl_validate_iv(&iv, &iv_len, EVP_CIPHER_iv_length(cipher_type) TSRMLS_CC);
outlen = data_len + EVP_CIPHER_block_size(cipher_type);
outbuf = emalloc(outlen + 1);
- EVP_EncryptInit(&cipher_ctx, cipher_type, key, iv);
+ EVP_EncryptInit(&cipher_ctx, cipher_type, key, (unsigned char *)iv);
EVP_EncryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
outlen = i;
if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
@@ -4636,25 +4694,28 @@ PHP_FUNCTION(openssl_encrypt)
if (key != (unsigned char*)password) {
efree(key);
}
- efree(iv);
+ if (free_iv) {
+ efree(iv);
+ }
}
/* }}} */
-/* {{{ proto string openssl_decrypt(string data, string method, string password [, bool raw_input=false])
+/* {{{ proto string openssl_decrypt(string data, string method, string password [, bool raw_input=false [, string $iv = '']])
Takes raw or base64 encoded string and dectupt it using given method and key */
PHP_FUNCTION(openssl_decrypt)
{
zend_bool raw_input = 0;
- char *data, *method, *password;
- int data_len, method_len, password_len;
+ char *data, *method, *password, *iv = "";
+ int data_len, method_len, password_len, iv_len = 0;
const EVP_CIPHER *cipher_type;
EVP_CIPHER_CTX cipher_ctx;
- int i, outlen, keylen, ivlen;
- unsigned char *outbuf, *key, *iv;
+ int i, outlen, keylen;
+ unsigned char *outbuf, *key;
int base64_str_len;
char *base64_str = NULL;
+ zend_bool free_iv;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, &data_len, &method, &method_len, &password, &password_len, &raw_input) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|bs", &data, &data_len, &method, &method_len, &password, &password_len, &raw_input, &iv, &iv_len) == FAILURE) {
return;
}
@@ -4684,14 +4745,12 @@ PHP_FUNCTION(openssl_decrypt)
key = (unsigned char*)password;
}
- ivlen = EVP_CIPHER_iv_length(cipher_type);
- iv = emalloc(ivlen);
- memset(iv, 0, ivlen);
+ free_iv = php_openssl_validate_iv(&iv, &iv_len, EVP_CIPHER_iv_length(cipher_type) TSRMLS_CC);
outlen = data_len + EVP_CIPHER_block_size(cipher_type);
outbuf = emalloc(outlen + 1);
- EVP_DecryptInit(&cipher_ctx, cipher_type, key, iv);
+ EVP_DecryptInit(&cipher_ctx, cipher_type, key, (unsigned char *)iv);
EVP_DecryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
outlen = i;
if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
@@ -4705,13 +4764,42 @@ PHP_FUNCTION(openssl_decrypt)
if (key != (unsigned char*)password) {
efree(key);
}
- efree(iv);
+ if (free_iv) {
+ efree(iv);
+ }
if (base64_str) {
efree(base64_str);
}
}
/* }}} */
+/* {{{ proto int openssl_cipher_iv_length(string $method) */
+PHP_FUNCTION(openssl_cipher_iv_length)
+{
+ char *method;
+ int method_len;
+ const EVP_CIPHER *cipher_type;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len) == FAILURE) {
+ return;
+ }
+
+ if (!method_len) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
+ RETURN_FALSE;
+ }
+
+ cipher_type = EVP_get_cipherbyname(method);
+ if (!cipher_type) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(EVP_CIPHER_iv_length(cipher_type));
+}
+/* }}} */
+
+
/* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
Computes shared sicret for public value of remote DH key and local DH key */
PHP_FUNCTION(openssl_dh_compute_key)
@@ -4771,27 +4859,23 @@ PHP_FUNCTION(openssl_random_pseudo_bytes)
ZVAL_BOOL(zstrong_result_returned, 0);
}
- buffer = emalloc(buffer_length);
-
- if (!buffer) {
- RETURN_FALSE;
- }
+ buffer = emalloc(buffer_length + 1);
#ifdef WINDOWS
RAND_screen();
#endif
if ((strong_result = RAND_pseudo_bytes(buffer, buffer_length)) < 0) {
- RETVAL_FALSE;
- } else {
- RETVAL_STRINGL((char *)buffer, buffer_length, 1);
+ efree(buffer);
+ RETURN_FALSE;
+ }
- if (zstrong_result_returned) {
- ZVAL_BOOL(zstrong_result_returned, strong_result);
- }
+ buffer[buffer_length] = 0;
+ RETVAL_STRINGL((char *)buffer, buffer_length, 0);
+ if (zstrong_result_returned) {
+ ZVAL_BOOL(zstrong_result_returned, strong_result);
}
- efree(buffer);
}
/* }}} */
diff --git a/ext/openssl/tests/011.phpt b/ext/openssl/tests/011.phpt
index 927360900..fdcc5e296 100644
--- a/ext/openssl/tests/011.phpt
+++ b/ext/openssl/tests/011.phpt
@@ -8,11 +8,16 @@ $data = "openssl_encrypt() and openssl_decrypt() tests";
$method = "AES-128-CBC";
$password = "openssl";
-$encrypted = openssl_encrypt($data, $method, $password);
-$output = openssl_decrypt($encrypted, $method, $password);
+$ivlen = openssl_cipher_iv_length($method);
+$iv = '';
+srand(time() + ((microtime(true) * 1000000) % 1000000));
+while(strlen($iv) < $ivlen) $iv .= chr(rand(0,255));
+
+$encrypted = openssl_encrypt($data, $method, $password, false, $iv);
+$output = openssl_decrypt($encrypted, $method, $password, false, $iv);
var_dump($output);
-$encrypted = openssl_encrypt($data, $method, $password, true);
-$output = openssl_decrypt($encrypted, $method, $password, true);
+$encrypted = openssl_encrypt($data, $method, $password, true, $iv);
+$output = openssl_decrypt($encrypted, $method, $password, true, $iv);
var_dump($output);
?>
--EXPECT--
diff --git a/ext/openssl/tests/bug48182.phpt b/ext/openssl/tests/bug48182.phpt
index 7471c4c5d..146c4c922 100644
--- a/ext/openssl/tests/bug48182.phpt
+++ b/ext/openssl/tests/bug48182.phpt
@@ -51,7 +51,7 @@ function ssl_async_client($port) {
$socket = stream_socket_client($host, $errno, $errstr, 10, $flags);
stream_set_blocking($socket, 0);
- while ($data) {
+ while ($socket && $data) {
$wrote = fwrite($socket, $data, strlen($data));
$data = substr($data, $wrote);
}
diff --git a/ext/openssl/tests/openssl_decrypt_error.phpt b/ext/openssl/tests/openssl_decrypt_error.phpt
index ea9cce2f0..233fa0c5b 100644
--- a/ext/openssl/tests/openssl_decrypt_error.phpt
+++ b/ext/openssl/tests/openssl_decrypt_error.phpt
@@ -8,8 +8,11 @@ $data = "openssl_decrypt() tests";
$method = "AES-128-CBC";
$password = "openssl";
$wrong = "wrong";
+$iv = str_repeat("\0", openssl_cipher_iv_length($method));
$encrypted = openssl_encrypt($data, $method, $password);
+var_dump($encrypted); /* Not passing $iv should be the same as all-NULL iv, but with a warning */
+var_dump(openssl_encrypt($data, $method, $password, false, $iv));
var_dump(openssl_decrypt($encrypted, $method, $wrong));
var_dump(openssl_decrypt($encrypted, $wrong, $password));
var_dump(openssl_decrypt($wrong, $method, $password));
@@ -21,6 +24,10 @@ var_dump(openssl_decrypt($encrypted, array(), $password));
var_dump(openssl_decrypt($encrypted, $method, array()));
?>
--EXPECTF--
+
+Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in %s on line %d
+string(44) "yof6cPPH4mLee6TOc0YQSrh4dvywMqxGUyjp0lV6+aM="
+string(44) "yof6cPPH4mLee6TOc0YQSrh4dvywMqxGUyjp0lV6+aM="
bool(false)
Warning: openssl_decrypt(): Unknown cipher algorithm in %s on line %d
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index 212c003a7..74a54d80b 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: xp_ssl.c 293036 2010-01-03 09:23:27Z sebastian $ */
+/* $Id: xp_ssl.c 300617 2010-06-20 16:33:16Z pajoye $ */
#include "php.h"
#include "ext/standard/file.h"
@@ -312,8 +312,12 @@ static inline int php_openssl_setup_crypto(php_stream *stream,
SSL_METHOD *method;
if (sslsock->ssl_handle) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream");
- return -1;
+ if (sslsock->s.is_blocked) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream");
+ return -1;
+ } else {
+ return 0;
+ }
}
/* need to do slightly different things, based on client/server method,
@@ -435,7 +439,8 @@ static inline int php_openssl_enable_crypto(php_stream *stream,
}
if (n <= 0) {
- retry = handle_ssl_error(stream, n, 1 TSRMLS_CC);
+ retry = handle_ssl_error(stream, n, sslsock->is_client || sslsock->s.is_blocked TSRMLS_CC);
+
} else {
break;
}
@@ -586,6 +591,8 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_
case STREAM_CRYPTO_METHOD_TLS_CLIENT:
sock->method = STREAM_CRYPTO_METHOD_TLS_SERVER;
break;
+ default:
+ break;
}
clisockdata->method = sock->method;