Skip to content

Commit 599d1dc

Browse files
bnoordhuisjuanarbol
authored andcommitted
crypto: ensure auth tag set for chacha20-poly1305
Because OpenSSL v1.x doesn't do that by itself (OpenSSL v3.x does.) Fixes: #45874 PR-URL: #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>
1 parent 9648b06 commit 599d1dc

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

src/crypto/crypto_cipher.cc

+8
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,14 @@ bool CipherBase::Final(std::unique_ptr<BackingStore>* out) {
901901
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get()))
902902
MaybePassAuthTagToOpenSSL();
903903

904+
// OpenSSL v1.x doesn't verify the presence of the auth tag so do
905+
// it ourselves, see https://github.com/nodejs/node/issues/45874.
906+
if (OPENSSL_VERSION_NUMBER < 0x30000000L && kind_ == kDecipher &&
907+
NID_chacha20_poly1305 == EVP_CIPHER_CTX_nid(ctx_.get()) &&
908+
auth_tag_state_ != kAuthTagPassedToOpenSSL) {
909+
return false;
910+
}
911+
904912
// In CCM mode, final() only checks whether authentication failed in update().
905913
// EVP_CipherFinal_ex must not be called and will fail.
906914
bool ok;

test/parallel/test-crypto-authenticated.js

+31
Original file line numberDiff line numberDiff line change
@@ -786,3 +786,34 @@ for (const test of TEST_CASES) {
786786
assert.strictEqual(plaintext.toString('hex'), testCase.plain);
787787
}
788788
}
789+
790+
// https://github.com/nodejs/node/issues/45874
791+
{
792+
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
793+
return algo === 'chacha20-poly1305' && tampered === false;
794+
});
795+
assert.strictEqual(rfcTestCases.length, 1);
796+
797+
const [testCase] = rfcTestCases;
798+
const key = Buffer.from(testCase.key, 'hex');
799+
const iv = Buffer.from(testCase.iv, 'hex');
800+
const aad = Buffer.from(testCase.aad, 'hex');
801+
const opt = { authTagLength: 16 };
802+
803+
const cipher = crypto.createCipheriv('chacha20-poly1305', key, iv, opt);
804+
const ciphertext = Buffer.concat([
805+
cipher.setAAD(aad).update(testCase.plain, 'hex'),
806+
cipher.final(),
807+
]);
808+
const authTag = cipher.getAuthTag();
809+
810+
assert.strictEqual(ciphertext.toString('hex'), testCase.ct);
811+
assert.strictEqual(authTag.toString('hex'), testCase.tag);
812+
813+
const decipher = crypto.createDecipheriv('chacha20-poly1305', key, iv, opt);
814+
decipher.setAAD(aad).update(ciphertext);
815+
816+
assert.throws(() => {
817+
decipher.final();
818+
}, /Unsupported state or unable to authenticate data/);
819+
}

0 commit comments

Comments
 (0)