summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2023-01-14 15:16:29 +0100
committerBeth Griggs <bethanyngriggs@gmail.com>2023-03-27 13:02:52 +0100
commit46175127884e749c3f3591de20384b6e337706c6 (patch)
treeaa993a3d7154bcb180288988d287056a07b259a9
parent809371a15f52a468089b9409abbd6d4879816e32 (diff)
downloadnode-new-46175127884e749c3f3591de20384b6e337706c6.tar.gz
crypto: ensure auth tag set for chacha20-poly1305
Because OpenSSL v1.x doesn't do that by itself (OpenSSL v3.x does.) Fixes: https://github.com/nodejs/node/issues/45874 PR-URL: https://github.com/nodejs/node/pull/46185 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: James M Snell <jasnell@gmail.com>
-rw-r--r--src/crypto/crypto_cipher.cc8
-rw-r--r--test/parallel/test-crypto-authenticated.js31
2 files changed, 39 insertions, 0 deletions
diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc
index f45eab1c22..10579cecd0 100644
--- a/src/crypto/crypto_cipher.cc
+++ b/src/crypto/crypto_cipher.cc
@@ -898,6 +898,14 @@ bool CipherBase::Final(std::unique_ptr<BackingStore>* out) {
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get()))
MaybePassAuthTagToOpenSSL();
+ // OpenSSL v1.x doesn't verify the presence of the auth tag so do
+ // it ourselves, see https://github.com/nodejs/node/issues/45874.
+ if (OPENSSL_VERSION_NUMBER < 0x30000000L && kind_ == kDecipher &&
+ NID_chacha20_poly1305 == EVP_CIPHER_CTX_nid(ctx_.get()) &&
+ auth_tag_state_ != kAuthTagPassedToOpenSSL) {
+ return false;
+ }
+
// In CCM mode, final() only checks whether authentication failed in update().
// EVP_CipherFinal_ex must not be called and will fail.
bool ok;
diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js
index 162b451c5b..d358f6b63c 100644
--- a/test/parallel/test-crypto-authenticated.js
+++ b/test/parallel/test-crypto-authenticated.js
@@ -786,3 +786,34 @@ for (const test of TEST_CASES) {
assert.strictEqual(plaintext.toString('hex'), testCase.plain);
}
}
+
+// https://github.com/nodejs/node/issues/45874
+{
+ const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
+ return algo === 'chacha20-poly1305' && tampered === false;
+ });
+ assert.strictEqual(rfcTestCases.length, 1);
+
+ const [testCase] = rfcTestCases;
+ const key = Buffer.from(testCase.key, 'hex');
+ const iv = Buffer.from(testCase.iv, 'hex');
+ const aad = Buffer.from(testCase.aad, 'hex');
+ const opt = { authTagLength: 16 };
+
+ const cipher = crypto.createCipheriv('chacha20-poly1305', key, iv, opt);
+ const ciphertext = Buffer.concat([
+ cipher.setAAD(aad).update(testCase.plain, 'hex'),
+ cipher.final(),
+ ]);
+ const authTag = cipher.getAuthTag();
+
+ assert.strictEqual(ciphertext.toString('hex'), testCase.ct);
+ assert.strictEqual(authTag.toString('hex'), testCase.tag);
+
+ const decipher = crypto.createDecipheriv('chacha20-poly1305', key, iv, opt);
+ decipher.setAAD(aad).update(ciphertext);
+
+ assert.throws(() => {
+ decipher.final();
+ }, /Unsupported state or unable to authenticate data/);
+}