mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
crypto: isolate cipher job errors
Use only errors captured by the cipher job when converting its result. Unrelated errors on the event loop thread must not turn a successful operation into a failure or trigger an assertion. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: https://github.com/nodejs/node/pull/66237 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
This commit is contained in:
1 parent
8c7346ac63
commit
fab9180ee5
2 files changed
+47
-5
No files matched your search
@@ -219,6 +219,7 @@ class CipherJob final : public CryptoJob<CipherTraits> {
|
||||
WebCryptoCipherMode cipher_mode() const { return cipher_mode_; }
|
||||
|
||||
void DoThreadPoolWork() override {
|
||||
ncrypto::ClearErrorOnReturn clear_error_on_return;
|
||||
const WebCryptoCipherStatus status =
|
||||
CipherTraits::DoCipher(
|
||||
AsyncWrap::env(),
|
||||
@@ -253,11 +254,7 @@ class CipherJob final : public CryptoJob<CipherTraits> {
|
||||
Environment* env = AsyncWrap::env();
|
||||
CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
|
||||
|
||||
if (errors->Empty())
|
||||
errors->Capture();
|
||||
|
||||
if (out_.size() > 0 || errors->Empty()) {
|
||||
CHECK(errors->Empty());
|
||||
if (errors->Empty()) {
|
||||
*err = v8::Undefined(env->isolate());
|
||||
*result = out_.ToArrayBuffer(env);
|
||||
if (result->IsEmpty()) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const { scrypt, scryptSync } = require('crypto');
|
||||
const { subtle } = globalThis.crypto;
|
||||
|
||||
if (typeof scryptSync !== 'function')
|
||||
common.skip('no scrypt support');
|
||||
|
||||
function failScrypt(sync) {
|
||||
// The failed parameter check leaves an error on the main thread's
|
||||
// OpenSSL error queue. Cipher jobs must only use their own errors.
|
||||
assert.throws(() => {
|
||||
if (sync) {
|
||||
scryptSync('password', 'salt', 64, { N: 2 ** 17 });
|
||||
} else {
|
||||
scrypt('password', 'salt', 64, { N: 2 ** 17 }, common.mustNotCall());
|
||||
}
|
||||
}, { code: 'ERR_CRYPTO_INVALID_SCRYPT_PARAMS' });
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const key = await subtle.importKey(
|
||||
'raw', new Uint8Array(16), 'AES-GCM', false, ['encrypt', 'decrypt']);
|
||||
const algorithm = { name: 'AES-GCM', iv: new Uint8Array(12) };
|
||||
|
||||
for (const sync of [true, false]) {
|
||||
for (const byteLength of [0, 16]) {
|
||||
const plaintext = new Uint8Array(byteLength);
|
||||
failScrypt(sync);
|
||||
const ciphertext = await subtle.encrypt(algorithm, key, plaintext);
|
||||
assert.strictEqual(ciphertext.byteLength, byteLength + 16);
|
||||
|
||||
failScrypt(sync);
|
||||
assert.deepStrictEqual(
|
||||
new Uint8Array(await subtle.decrypt(algorithm, key, ciphertext)),
|
||||
plaintext);
|
||||
}
|
||||
}
|
||||
})().then(common.mustCall());
|
||||
Reference in new issue
Block a user