diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 0b6dfa65bd1eee..bba4b8663d2d4c 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -807,6 +807,18 @@ Importing assert directly is not recommended as the exposed functions will use loose equality checks. Use `require('assert').strict` instead. The API is the same as the legacy assert but it will always use strict equality checks. + +### DEP0090: Invalid GCM authentication tag lengths + +Type: Runtime + +Node.js supports all GCM authentication tag lengths which are accepted by +OpenSSL when calling [`decipher.setAuthTag()`][]. This behavior will change in +a future version at which point only authentication tag lengths of 128, 120, +112, 104, 96, 64, and 32 bits will be allowed. Authentication tags whose length +is not included in this list will be considered invalid in compliance with +[NIST SP 800-38D][]. + [`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size [`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array [`Buffer.from(buffer)`]: buffer.html#buffer_class_method_buffer_from_buffer @@ -821,6 +833,7 @@ same as the legacy assert but it will always use strict equality checks. [`console.log()`]: console.html#console_console_log_data_args [`crypto.createCredentials()`]: crypto.html#crypto_crypto_createcredentials_details [`crypto.pbkdf2()`]: crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback +[`decipher.setAuthTag()`]: crypto.html#crypto_decipher_setauthtag_buffer [`domain`]: domain.html [`ecdh.setPublicKey()`]: crypto.html#crypto_ecdh_setpublickey_publickey_encoding [`emitter.listenerCount(eventName)`]: events.html#events_emitter_listenercount_eventname @@ -871,4 +884,5 @@ same as the legacy assert but it will always use strict equality checks. [alloc_unsafe_size]: buffer.html#buffer_class_method_buffer_allocunsafe_size [from_arraybuffer]: buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length [from_string_encoding]: buffer.html#buffer_class_method_buffer_from_string_encoding +[NIST SP 800-38D]: http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf [`REPLServer.clearBufferedCommand()`]: repl.html#repl_replserver_clearbufferedcommand diff --git a/src/node_crypto.cc b/src/node_crypto.cc index d512266bffdb37..b572c90aa50037 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3157,10 +3157,11 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { // Restrict GCM tag lengths according to NIST 800-38d, page 9. unsigned int tag_len = Buffer::Length(args[0]); if (tag_len > 16 || (tag_len < 12 && tag_len != 8 && tag_len != 4)) { - ProcessEmitWarning(cipher->env(), - "Permitting authentication tag lengths of %u bytes is deprecated. " - "Valid GCM tag lengths are 4, 8, 12, 13, 14, 15, 16.", - tag_len); + char msg[125]; + snprintf(msg, sizeof(msg), + "Permitting authentication tag lengths of %u bytes is deprecated. " + "Valid GCM tag lengths are 4, 8, 12, 13, 14, 15, 16.", tag_len); + ProcessEmitDeprecationWarning(cipher->env(), msg, "DEP0090"); } // Note: we don't use std::max() here to work around a header conflict. diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index 221009cb4a7a25..384044210d5b85 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -335,13 +335,17 @@ const errMessages = { const ciphers = crypto.getCiphers(); -common.expectWarning('Warning', (common.hasFipsCrypto ? [] : [ - 'Use Cipheriv for counter mode of aes-192-gcm' -]).concat( - [0, 1, 2, 6, 9, 10, 11, 17] +const expectedWarnings = common.hasFipsCrypto ? + [] : ['Use Cipheriv for counter mode of aes-192-gcm']; + +const expectedDeprecationWarnings = [0, 1, 2, 6, 9, 10, 11, 17] .map((i) => `Permitting authentication tag lengths of ${i} bytes is ` + - 'deprecated. Valid GCM tag lengths are 4, 8, 12, 13, 14, 15, 16.') -)); + 'deprecated. Valid GCM tag lengths are 4, 8, 12, 13, 14, 15, 16.'); + +common.expectWarning({ + Warning: expectedWarnings, + DeprecationWarning: expectedDeprecationWarnings +}); for (const test of TEST_CASES) { if (!ciphers.includes(test.algo)) {