diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index bed4d48d118d51..dadf0381b58fa5 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -2642,8 +2642,6 @@ DataPointer hkdf(const Digest& md, const Buffer& info, const Buffer& salt, size_t length) { - ClearErrorOnReturn clearErrorOnReturn; - if (!checkHkdfLength(md, length) || info.len > INT_MAX || salt.len > INT_MAX) { return {}; @@ -2714,8 +2712,6 @@ DataPointer scrypt(const Buffer& pass, uint64_t p, uint64_t maxmem, size_t length) { - ClearErrorOnReturn clearErrorOnReturn; - if (pass.len > INT_MAX || salt.len > INT_MAX) { return {}; } @@ -2742,8 +2738,6 @@ DataPointer pbkdf2(const Digest& md, const Buffer& salt, uint32_t iterations, size_t length) { - ClearErrorOnReturn clearErrorOnReturn; - if (pass.len > INT_MAX || salt.len > INT_MAX || length > INT_MAX) { return {}; } @@ -2775,8 +2769,6 @@ DataPointer argon2(const Buffer& pass, const Buffer& secret, const Buffer& ad, Argon2Type type) { - ClearErrorOnReturn clearErrorOnReturn; - std::string_view algorithm; switch (type) { case Argon2Type::ARGON2I: @@ -2793,15 +2785,24 @@ DataPointer argon2(const Buffer& pass, return {}; } - // creates a new library context to avoid locking when running concurrently - auto ctx = DeleteFnPtr{OSSL_LIB_CTX_new()}; - if (!ctx) { - return {}; - } + // A new library context is only needed for OSSL_set_max_threads(), which is + // per-context. It inherits no configuration, so availability is checked + // against the default context, otherwise Argon2 works in FIPS mode. + DeleteFnPtr ctx; + if (lanes > 1) { + if (!DeleteFnPtr{ + EVP_KDF_fetch(nullptr, algorithm.data(), nullptr)}) { + return {}; + } - // required if threads > 1 - if (lanes > 1 && OSSL_set_max_threads(ctx.get(), lanes) != 1) { - return {}; + ctx.reset(OSSL_LIB_CTX_new()); + if (!ctx) { + return {}; + } + + if (OSSL_set_max_threads(ctx.get(), lanes) != 1) { + return {}; + } } auto kdf = DeleteFnPtr{ diff --git a/src/crypto/crypto_argon2.cc b/src/crypto/crypto_argon2.cc index 42c5179f2b2340..ed669ba0a557d3 100644 --- a/src/crypto/crypto_argon2.cc +++ b/src/crypto/crypto_argon2.cc @@ -150,6 +150,7 @@ bool Argon2Traits::DeriveBits(Environment* env, config.type); if (!dp) { + errors->Capture(); errors->Insert(NodeCryptoError::ARGON2_FAILED); return false; } diff --git a/src/crypto/crypto_hkdf.cc b/src/crypto/crypto_hkdf.cc index eb40ddad41c6e3..d55d2e9a2a08bd 100644 --- a/src/crypto/crypto_hkdf.cc +++ b/src/crypto/crypto_hkdf.cc @@ -130,6 +130,7 @@ bool HKDFTraits::DeriveBits(Environment* env, }, params.length); if (!dp) { + errors->Capture(); errors->Insert(NodeCryptoError::HKDF_FAILED); return false; } diff --git a/src/crypto/crypto_pbkdf2.cc b/src/crypto/crypto_pbkdf2.cc index 5c3fc438774334..0a1c5142a2fb89 100644 --- a/src/crypto/crypto_pbkdf2.cc +++ b/src/crypto/crypto_pbkdf2.cc @@ -139,6 +139,7 @@ bool PBKDF2Traits::DeriveBits(Environment* env, params.length); if (!dp) { + errors->Capture(); errors->Insert(NodeCryptoError::PBKDF2_FAILED); return false; } diff --git a/src/crypto/crypto_scrypt.cc b/src/crypto/crypto_scrypt.cc index 91ed9fee71f052..1260ac811df496 100644 --- a/src/crypto/crypto_scrypt.cc +++ b/src/crypto/crypto_scrypt.cc @@ -137,6 +137,7 @@ bool ScryptTraits::DeriveBits(Environment* env, params.length); if (!dp) { + errors->Capture(); errors->Insert(NodeCryptoError::SCRYPT_FAILED); return false; } diff --git a/test/parallel/test-crypto-argon2-job.js b/test/parallel/test-crypto-argon2-job.js index 34db5e4660c11c..37a0127958cf48 100644 --- a/test/parallel/test-crypto-argon2-job.js +++ b/test/parallel/test-crypto-argon2-job.js @@ -29,19 +29,31 @@ const empty = Buffer.alloc(0); // Parameters that OpenSSL's Argon2 KDF rejects. const badParams = [ - { lanes: 0, keylen: 32, memcost: 16, iter: 1 }, // lanes < 1 - { lanes: 1, keylen: 32, memcost: 0, iter: 1 }, // memcost == 0 - { lanes: 1, keylen: 32, memcost: 16, iter: 0 }, // iter == 0 + { lanes: 0, keylen: 32, memcost: 16, iter: 1, + code: 'ERR_OSSL_INVALID_THREAD_POOL_SIZE', reason: /invalid thread pool size/ }, + { lanes: 1, keylen: 32, memcost: 0, iter: 1, + code: 'ERR_OSSL_INVALID_MEMORY_SIZE', reason: /invalid memory size/ }, + { lanes: 1, keylen: 32, memcost: 16, iter: 0, + code: 'ERR_OSSL_INVALID_ITERATION_COUNT', reason: /invalid iteration count/ }, ]; -for (const { lanes, keylen, memcost, iter } of badParams) { +function assertError(err, { code, reason }) { + assert.ok(err); + assert.match(err.message, /Argon2 derivation failed/); + assert.strictEqual(err.code, code); + assert.ok(err.opensslErrorStack.some((msg) => reason.test(msg)), + `did not find ${reason} in ${err.opensslErrorStack}`); +} + +for (const params of badParams) { + const { lanes, keylen, memcost, iter } = params; + { const job = new Argon2Job( kCryptoJobSync, pass, salt, lanes, keylen, memcost, iter, empty, empty, kTypeArgon2id); const { 0: err, 1: result } = job.run(); - assert.ok(err); - assert.match(err.message, /Argon2 derivation failed/); + assertError(err, params); assert.strictEqual(result, undefined); } @@ -50,8 +62,7 @@ for (const { lanes, keylen, memcost, iter } of badParams) { kCryptoJobAsync, pass, salt, lanes, keylen, memcost, iter, empty, empty, kTypeArgon2id); job.ondone = common.mustCall((err, result) => { - assert.ok(err); - assert.match(err.message, /Argon2 derivation failed/); + assertError(err, params); assert.strictEqual(result, undefined); }); job.run(); diff --git a/test/parallel/test-crypto-no-algorithm.js b/test/parallel/test-crypto-no-algorithm.js index 96236a976a89ef..3a9473dfb165e3 100644 --- a/test/parallel/test-crypto-no-algorithm.js +++ b/test/parallel/test-crypto-no-algorithm.js @@ -26,6 +26,24 @@ if (isMainThread) { `did not find ${expected} in ${err.opensslErrorStack}`); } })); + + const derivations = [ + ['HKDF', () => crypto.hkdfSync('sha256', Buffer.alloc(32), Buffer.alloc(8), + Buffer.alloc(0), 32)], + ['PBKDF2', () => crypto.pbkdf2Sync('secret', Buffer.alloc(16), 1000, 32, + 'sha256')], + ]; + for (const { 0: name, 1: derive } of derivations) { + try { + derive(); + } catch (err) { + assert.match(err.message, /derivation failed/); + assert.strictEqual(err.code, 'ERR_OSSL_EVP_UNSUPPORTED', `${name}: ${err.code}`); + const expected = /digital envelope routines::unsupported/; + assert(err.opensslErrorStack.some((msg) => expected.test(msg)), + `${name}: did not find ${expected} in ${err.opensslErrorStack}`); + } + } } {