diff options
author | Jakub Zelenka <bukka@php.net> | 2017-06-25 18:08:50 +0100 |
---|---|---|
committer | Jakub Zelenka <bukka@php.net> | 2017-06-25 18:08:50 +0100 |
commit | 0c707fcb1051c5dfaae22b638bfbebf8c44543b1 (patch) | |
tree | e9d227ea1e3387d9a8333e8e7203f8ec30fcc060 /ext/openssl | |
parent | bda0f4e8dce25280ee9db4b6058b80b74a80991f (diff) | |
download | php-git-0c707fcb1051c5dfaae22b638bfbebf8c44543b1.tar.gz |
Add OPENSSL_DONT_ZERO_PAD_KEY constant to prevent key padding
It fixes bug #71917 (openssl_open() returns junk on envelope < 16 bytes)
and bug #72362 (OpenSSL Blowfish encryption is incorrect for short
keys).
Diffstat (limited to 'ext/openssl')
-rw-r--r-- | ext/openssl/openssl.c | 39 | ||||
-rw-r--r-- | ext/openssl/php_openssl.h | 1 | ||||
-rw-r--r-- | ext/openssl/tests/bug71917.phpt | 25 | ||||
-rw-r--r-- | ext/openssl/tests/bug72362.phpt | 14 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_decrypt_basic.phpt | 5 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_encrypt_error.phpt | 6 |
6 files changed, 74 insertions, 16 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index cbb2d3a78b..524e6fca6d 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1511,6 +1511,7 @@ PHP_MINIT_FUNCTION(openssl) REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_DONT_ZERO_PAD_KEY", OPENSSL_DONT_ZERO_PAD_KEY, CONST_CS|CONST_PERSISTENT); #ifndef OPENSSL_NO_TLSEXT /* SNI support included */ @@ -6280,20 +6281,7 @@ static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type, int key_len, password_len; size_t max_iv_len; - /* check and set key */ - password_len = (int) *ppassword_len; - key_len = EVP_CIPHER_key_length(cipher_type); - if (key_len > password_len) { - key = emalloc(key_len); - memset(key, 0, key_len); - memcpy(key, *ppassword, password_len); - *ppassword = (char *) key; - *ppassword_len = key_len; - *free_password = 1; - } else { - key = (unsigned char*)*ppassword; - *free_password = 0; - } + *free_password = 0; max_iv_len = EVP_CIPHER_iv_length(cipher_type); if (enc && *piv_len == 0 && max_iv_len > 0 && !mode->is_aead) { @@ -6318,9 +6306,28 @@ static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type, return FAILURE; } } - if (password_len > key_len && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) { - php_openssl_store_errors(); + /* check and set key */ + password_len = (int) *ppassword_len; + key_len = EVP_CIPHER_key_length(cipher_type); + if (key_len > password_len) { + if ((OPENSSL_DONT_ZERO_PAD_KEY & options) && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Key length cannot be set for the cipher method"); + return FAILURE; + } + key = emalloc(key_len); + memset(key, 0, key_len); + memcpy(key, *ppassword, password_len); + *ppassword = (char *) key; + *ppassword_len = key_len; + *free_password = 1; + } else { + if (password_len > key_len && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) { + php_openssl_store_errors(); + } + key = (unsigned char*)*ppassword; } + if (!EVP_CipherInit_ex(cipher_ctx, NULL, NULL, key, (unsigned char *)*piv, enc)) { php_openssl_store_errors(); return FAILURE; diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 08f240e8e4..bab7159512 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -31,6 +31,7 @@ extern zend_module_entry openssl_module_entry; #define OPENSSL_RAW_DATA 1 #define OPENSSL_ZERO_PADDING 2 +#define OPENSSL_DONT_ZERO_PAD_KEY 4 #define OPENSSL_ERROR_X509_PRIVATE_KEY_VALUES_MISMATCH 0x0B080074 diff --git a/ext/openssl/tests/bug71917.phpt b/ext/openssl/tests/bug71917.phpt new file mode 100644 index 0000000000..d4415b3e32 --- /dev/null +++ b/ext/openssl/tests/bug71917.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #71917: openssl_open() returns junk on envelope < 16 bytes +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip openssl not loaded"); +?> +--FILE-- +<?php +function test($envkey) { + $publicKey = "file://" . dirname(__FILE__) . "/public.key"; + $privateKey = "file://" . dirname(__FILE__) . "/private_rsa_1024.key"; + openssl_public_encrypt($envkey, $envelope, $publicKey); + $sealed = openssl_encrypt('plaintext', 'rc4', $envkey, OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY); + openssl_open($sealed, $output, $envelope, $privateKey, 'rc4'); + var_dump($output === 'plaintext'); +} + +// works - key of 16 bytes +test('1234567890123456i'); +// fails - key of 15 bytes +test('123456789012345'); +?> +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/openssl/tests/bug72362.phpt b/ext/openssl/tests/bug72362.phpt new file mode 100644 index 0000000000..40acdbed0c --- /dev/null +++ b/ext/openssl/tests/bug72362.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #72362: OpenSSL Blowfish encryption is incorrect for short keys +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip openssl not loaded"); +?> +--FILE-- +<?php +var_dump(bin2hex(openssl_encrypt("this is a test string","bf-ecb","12345678", OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY))); +var_dump(bin2hex(openssl_encrypt("this is a test string","bf-ecb","1234567812345678" , OPENSSL_RAW_DATA))); +?> +--EXPECT-- +string(48) "e3214d1b16e574828c8a3e222202dde81afd1ad2cb165ab3" +string(48) "e3214d1b16e574828c8a3e222202dde81afd1ad2cb165ab3" diff --git a/ext/openssl/tests/openssl_decrypt_basic.phpt b/ext/openssl/tests/openssl_decrypt_basic.phpt index 1c29767cc5..37d17150fb 100644 --- a/ext/openssl/tests/openssl_decrypt_basic.phpt +++ b/ext/openssl/tests/openssl_decrypt_basic.phpt @@ -24,8 +24,13 @@ $padded_data = $data . str_repeat(' ', 16 - (strlen($data) % 16)); $encrypted = openssl_encrypt($padded_data, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv); $output = openssl_decrypt($encrypted, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv); var_dump(rtrim($output)); +// if we want to prefer variable length cipher setting +$encrypted = openssl_encrypt($data, "bf-ecb", $password, OPENSSL_DONT_ZERO_PAD_KEY); +$output = openssl_decrypt($encrypted, "bf-ecb", $password, OPENSSL_DONT_ZERO_PAD_KEY); +var_dump($output); ?> --EXPECT-- string(45) "openssl_encrypt() and openssl_decrypt() tests" string(45) "openssl_encrypt() and openssl_decrypt() tests" string(45) "openssl_encrypt() and openssl_decrypt() tests" +string(45) "openssl_encrypt() and openssl_decrypt() tests" diff --git a/ext/openssl/tests/openssl_encrypt_error.phpt b/ext/openssl/tests/openssl_encrypt_error.phpt index 791c431211..ea69ad9ee2 100644 --- a/ext/openssl/tests/openssl_encrypt_error.phpt +++ b/ext/openssl/tests/openssl_encrypt_error.phpt @@ -23,6 +23,9 @@ var_dump(openssl_encrypt($data, $method, $arr)); // invalid using of an authentication tag var_dump(openssl_encrypt($data, $method, $password, 0, $iv, $wrong)); + +// padding of the key is disabled +var_dump(openssl_encrypt($data, $method, $password, OPENSSL_DONT_ZERO_PAD_KEY, $iv)); ?> --EXPECTF-- Warning: openssl_encrypt(): Unknown cipher algorithm in %s on line %d @@ -48,3 +51,6 @@ NULL Warning: openssl_encrypt(): The authenticated tag cannot be provided for cipher that doesn not support AEAD in %s on line %d string(44) "iPR4HulskuaP5Z6me5uImk6BqVyJG73+63tkPauVZYk=" + +Warning: openssl_encrypt(): Key length cannot be set for the cipher method in %s on line %d +bool(false) |