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
  • Loading branch information
bnoordhuis committed Jan 12, 2023
1 parent 91ca2d4 commit df8df65
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/crypto/crypto_cipher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,15 @@ 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 df8df65

Please sign in to comment.