Skip to content

Commit

Permalink
crypto: ensure auth tag set for chacha20-poly1305
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
bnoordhuis authored and juanarbol committed Jan 31, 2023
1 parent 9648b06 commit 599d1dc
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/crypto/crypto_cipher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,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;
Expand Down
31 changes: 31 additions & 0 deletions test/parallel/test-crypto-authenticated.js
Original file line number Diff line number Diff line change
Expand Up @@ -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/);
}

0 comments on commit 599d1dc

Please sign in to comment.