crypto: disable ciphers not supported by EVP

OpenSSL lists certain ciphers as not conforming with the standard
EVP AEAD interface and these ciphers should be avoided,

    aes-128-cbc-hmac-sha1
    aes-128-cbc-hmac-sha256
    aes-256-cbc-hmac-sha1
    aes-256-cbc-hmac-sha256

While experimenting with these, the cipher text produced by Node
for `aes-128-cbc-hmac-sha1` does not differ from cipher text
produced by `aes-128-cbc` meaning that the HMAC is not automatically
taken into account. Since there is no facility to set the HMAC key
in Node, it's best to have these disabled when using crypto.Cipher
as all usage is wrong by definition.

Fixes: https://github.com/nodejs/node/issues/43040
This commit is contained in:
Adam Majer 2022-06-22 13:41:16 +02:00
parent 3d0a0b6825
commit 57f019481f
4 changed files with 36 additions and 4 deletions

View File

@ -791,6 +791,14 @@ when an error occurs (and is caught) during the creation of the
context, for example, when the allocation fails or the maximum call stack
size is reached when the context is created.
<a id="ERR_CRYPTO_CIPHER_DISABLED"></a>
### `ERR_CRYPTO_CIPHER_DISABLED`
A cipher was requested that does not conform to OpenSSL's standard
EVP interface for AEAD ciphers and requires usage of undocumented
interfaces.
<a id="ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED"></a>
### `ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED`

View File

@ -24,6 +24,7 @@ const {
const {
codes: {
ERR_CRYPTO_CIPHER_DISABLED,
ERR_CRYPTO_INVALID_STATE,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
@ -108,6 +109,14 @@ function getUIntOption(options, key) {
}
function createCipherBase(cipher, credential, options, decipher, iv) {
switch (cipher.toLowerCase()) {
case 'aes-128-cbc-hmac-sha1':
case 'aes-128-cbc-hmac-sha256':
case 'aes-256-cbc-hmac-sha1':
case 'aes-256-cbc-hmac-sha256':
throw new ERR_CRYPTO_CIPHER_DISABLED(cipher);
}
const authTagLength = getUIntOption(options, 'authTagLength');
this[kHandle] = new CipherBase(decipher);
if (iv === undefined) {

View File

@ -936,6 +936,9 @@ E('ERR_CHILD_PROCESS_STDIO_MAXBUFFER', '%s maxBuffer length exceeded',
E('ERR_CONSOLE_WRITABLE_STREAM',
'Console expects a writable stream instance for %s', TypeError);
E('ERR_CONTEXT_NOT_INITIALIZED', 'context used is not initialized', Error);
E('ERR_CRYPTO_CIPHER_DISABLED',
'Cipher %s is disabled as it\'s not compatible with OpenSSL\'s ' +
'EVP AEAD interfaces', Error);
E('ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
'Custom engines not supported by this OpenSSL', Error);
E('ERR_CRYPTO_ECDH_INVALID_FORMAT', 'Invalid ECDH format: %s', TypeError);

View File

@ -129,10 +129,22 @@ for (const algo of cryptoCiphers) {
options = { authTagLength: 8 };
else if (mode === 'ocb' || algo === 'chacha20-poly1305')
options = { authTagLength: 16 };
crypto.createCipheriv(algo,
crypto.randomBytes(keyLength),
crypto.randomBytes(ivLength || 0),
options);
const create_cipher = () =>
crypto.createCipheriv(algo,
crypto.randomBytes(keyLength),
crypto.randomBytes(ivLength || 0),
options);
// Disabled ciphers will throw
if (algo.includes('hmac-sha'))
assert.throws(create_cipher, {
code: 'ERR_CRYPTO_CIPHER_DISABLED',
name: 'Error',
message: `Cipher ${algo} is disabled as it's not compatible with OpenSSL's EVP AEAD interfaces`
});
else
create_cipher();
}
// Assume that we have at least AES256-SHA.