From c7c5011a75b2c293394155077bde26c846400b1f Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Mon, 7 Nov 2022 07:35:35 +0100 Subject: [PATCH] crypto: handle more webcrypto errors with OperationError MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/45320 Reviewed-By: Yagiz Nizipli Reviewed-By: Antoine du Hamel Reviewed-By: Tobias Nießen Backport-PR-URL: https://github.com/nodejs/node/pull/47336 --- lib/internal/crypto/aes.js | 8 ++++---- lib/internal/crypto/cfrg.js | 4 ++-- lib/internal/crypto/diffiehellman.js | 6 +++++- lib/internal/crypto/ec.js | 4 ++-- lib/internal/crypto/hash.js | 2 +- lib/internal/crypto/mac.js | 2 +- lib/internal/crypto/rsa.js | 6 +++--- lib/internal/crypto/util.js | 11 ++++++++--- test/parallel/test-webcrypto-digest.js | 2 +- 9 files changed, 27 insertions(+), 18 deletions(-) diff --git a/lib/internal/crypto/aes.js b/lib/internal/crypto/aes.js index 79ca61c5ff2097..e716caedd050de 100644 --- a/lib/internal/crypto/aes.js +++ b/lib/internal/crypto/aes.js @@ -124,7 +124,7 @@ function asyncAesCtrCipher(mode, key, data, { counter, length }) { 'OperationError'); } - return jobPromise(new AESCipherJob( + return jobPromise(() => new AESCipherJob( kCryptoJobAsync, mode, key[kKeyObject][kHandle], @@ -137,7 +137,7 @@ function asyncAesCtrCipher(mode, key, data, { counter, length }) { function asyncAesCbcCipher(mode, key, data, { iv }) { iv = getArrayBufferOrView(iv, 'algorithm.iv'); validateByteLength(iv, 'algorithm.iv', 16); - return jobPromise(new AESCipherJob( + return jobPromise(() => new AESCipherJob( kCryptoJobAsync, mode, key[kKeyObject][kHandle], @@ -147,7 +147,7 @@ function asyncAesCbcCipher(mode, key, data, { iv }) { } function asyncAesKwCipher(mode, key, data) { - return jobPromise(new AESCipherJob( + return jobPromise(() => new AESCipherJob( kCryptoJobAsync, mode, key[kKeyObject][kHandle], @@ -201,7 +201,7 @@ function asyncAesGcmCipher( break; } - return jobPromise(new AESCipherJob( + return jobPromise(() => new AESCipherJob( kCryptoJobAsync, mode, key[kKeyObject][kHandle], diff --git a/lib/internal/crypto/cfrg.js b/lib/internal/crypto/cfrg.js index 17358c7ccca23d..98e236052f555e 100644 --- a/lib/internal/crypto/cfrg.js +++ b/lib/internal/crypto/cfrg.js @@ -194,7 +194,7 @@ async function cfrgGenerateKey(algorithm, extractable, keyUsages) { function cfrgExportKey(key, format) { emitExperimentalWarning(`The ${key.algorithm.name} Web Crypto API algorithm`); - return jobPromise(new ECKeyExportJob( + return jobPromise(() => new ECKeyExportJob( kCryptoJobAsync, format, key[kKeyObject][kHandle])); @@ -323,7 +323,7 @@ function eddsaSignVerify(key, data, { name, context }, signature) { } } - return jobPromise(new SignJob( + return jobPromise(() => new SignJob( kCryptoJobAsync, mode, key[kKeyObject][kHandle], diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js index 62107a31a4f9e8..ac37e45a8b6b99 100644 --- a/lib/internal/crypto/diffiehellman.js +++ b/lib/internal/crypto/diffiehellman.js @@ -377,7 +377,11 @@ async function asyncDeriveBitsECDH(algorithm, baseKey, length) { key.algorithm.name === 'ECDH' ? baseKey.algorithm.namedCurve : baseKey.algorithm.name, key[kKeyObject][kHandle], baseKey[kKeyObject][kHandle], (err, bits) => { - if (err) return reject(err); + if (err) { + return reject(lazyDOMException( + 'The operation failed for an operation-specific reason', + 'OperationError')); + } resolve(bits); }); }); diff --git a/lib/internal/crypto/ec.js b/lib/internal/crypto/ec.js index ed7484dbbb596e..e39d443941dba7 100644 --- a/lib/internal/crypto/ec.js +++ b/lib/internal/crypto/ec.js @@ -151,7 +151,7 @@ async function ecGenerateKey(algorithm, extractable, keyUsages) { } function ecExportKey(key, format) { - return jobPromise(new ECKeyExportJob( + return jobPromise(() => new ECKeyExportJob( kCryptoJobAsync, format, key[kKeyObject][kHandle])); @@ -286,7 +286,7 @@ function ecdsaSignVerify(key, data, { name, hash }, signature) { throw new ERR_MISSING_OPTION('algorithm.hash'); const hashname = normalizeHashName(hash.name); - return jobPromise(new SignJob( + return jobPromise(() => new SignJob( kCryptoJobAsync, mode, key[kKeyObject][kHandle], diff --git a/lib/internal/crypto/hash.js b/lib/internal/crypto/hash.js index 956053af0a8c2c..72d127b37cbeb6 100644 --- a/lib/internal/crypto/hash.js +++ b/lib/internal/crypto/hash.js @@ -183,7 +183,7 @@ async function asyncDigest(algorithm, data) { case 'SHA-384': // Fall through case 'SHA-512': - return jobPromise(new HashJob( + return jobPromise(() => new HashJob( kCryptoJobAsync, normalizeHashName(algorithm.name), data, diff --git a/lib/internal/crypto/mac.js b/lib/internal/crypto/mac.js index 15b3378e2eda64..f08ed611142bc0 100644 --- a/lib/internal/crypto/mac.js +++ b/lib/internal/crypto/mac.js @@ -184,7 +184,7 @@ async function hmacImportKey( function hmacSignVerify(key, data, algorithm, signature) { const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify; - return jobPromise(new HmacJob( + return jobPromise(() => new HmacJob( kCryptoJobAsync, mode, normalizeHashName(key.algorithm.hash.name), diff --git a/lib/internal/crypto/rsa.js b/lib/internal/crypto/rsa.js index fa6928e4d78f06..3fe7f4fef4aef3 100644 --- a/lib/internal/crypto/rsa.js +++ b/lib/internal/crypto/rsa.js @@ -116,7 +116,7 @@ function rsaOaepCipher(mode, key, data, { label }) { validateMaxBufferLength(label, 'algorithm.label'); } - return jobPromise(new RSACipherJob( + return jobPromise(() => new RSACipherJob( kCryptoJobAsync, mode, key[kKeyObject][kHandle], @@ -224,7 +224,7 @@ async function rsaKeyGenerate( } function rsaExportKey(key, format) { - return jobPromise(new RSAKeyExportJob( + return jobPromise(() => new RSAKeyExportJob( kCryptoJobAsync, format, key[kKeyObject][kHandle], @@ -347,7 +347,7 @@ function rsaSignVerify(key, data, { saltLength }, signature) { if (key.type !== type) throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError'); - return jobPromise(new SignJob( + return jobPromise(() => new SignJob( kCryptoJobAsync, signature === undefined ? kSignJobModeSign : kSignJobModeVerify, key[kKeyObject][kHandle], diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index dbd816cff99e9f..b6b84c441ad742 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -287,10 +287,15 @@ function onDone(resolve, reject, err, result) { resolve(result); } -function jobPromise(job) { +function jobPromise(getJob) { return new Promise((resolve, reject) => { - job.ondone = FunctionPrototypeBind(onDone, job, resolve, reject); - job.run(); + try { + const job = getJob(); + job.ondone = FunctionPrototypeBind(onDone, job, resolve, reject); + job.run(); + } catch (err) { + onDone(resolve, reject, err); + } }); } diff --git a/test/parallel/test-webcrypto-digest.js b/test/parallel/test-webcrypto-digest.js index b8680564d1a1a3..25b78500b7d346 100644 --- a/test/parallel/test-webcrypto-digest.js +++ b/test/parallel/test-webcrypto-digest.js @@ -83,7 +83,7 @@ Promise.all([1, [], {}, null, undefined].map((i) => // addition to the API, and is added as a support for future additional // hash algorithms that support variable digest output lengths. assert.rejects(subtle.digest({ name: 'SHA-512', length: 510 }, kData), { - message: /Digest method not supported/ + name: 'OperationError', }).then(common.mustCall()); const kSourceData = {