diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 7e7222996f941d..68efa676f0c475 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3806,9 +3806,17 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { return env->ThrowError("Attempting to set auth tag in unsupported state"); } - // FIXME(bnoordhuis) Throw when buffer length is not a valid tag size. + // 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); + } + // Note: we don't use std::max() here to work around a header conflict. - cipher->auth_tag_len_ = Buffer::Length(args[0]); + cipher->auth_tag_len_ = tag_len; if (cipher->auth_tag_len_ > sizeof(cipher->auth_tag_)) cipher->auth_tag_len_ = sizeof(cipher->auth_tag_); diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index c03aa0efce54e0..df6b4316390594 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -335,6 +335,14 @@ 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] + .map((i) => `Permitting authentication tag lengths of ${i} bytes is ` + + 'deprecated. Valid GCM tag lengths are 4, 8, 12, 13, 14, 15, 16.') +)); + for (const i in TEST_CASES) { const test = TEST_CASES[i]; @@ -476,3 +484,14 @@ for (const i in TEST_CASES) { assert.throws(() => encrypt.setAAD(Buffer.from('123', 'ascii')), errMessages.state); } + +// GCM only supports specific authentication tag lengths, invalid lengths should +// produce warnings. +{ + for (const length of [0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]) { + const decrypt = crypto.createDecipheriv('aes-256-gcm', + 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', + 'qkuZpJWCewa6Szih'); + decrypt.setAuthTag(Buffer.from('1'.repeat(length))); + } +}