diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2023-01-14 15:16:29 +0100 |
---|---|---|
committer | Beth Griggs <bethanyngriggs@gmail.com> | 2023-03-27 13:02:52 +0100 |
commit | 46175127884e749c3f3591de20384b6e337706c6 (patch) | |
tree | aa993a3d7154bcb180288988d287056a07b259a9 | |
parent | 809371a15f52a468089b9409abbd6d4879816e32 (diff) | |
download | node-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.cc | 8 | ||||
-rw-r--r-- | test/parallel/test-crypto-authenticated.js | 31 |
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/); +} |