Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/api/sqlite.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ added: v22.5.0
-->

Closes the database connection. An exception is thrown if the database is not
open. This method is a wrapper around [`sqlite3_close_v2()`][].
open. An [`ERR_INVALID_STATE`][] error is thrown if the method is called while
a statement is executing, such as inside a user-defined function, an aggregate
function, or an authorizer callback. This method is a wrapper around
[`sqlite3_close_v2()`][].

### `database.loadExtension(path[, entryPoint])`

Expand Down
11 changes: 2 additions & 9 deletions doc/api/synopsis.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,8 @@ Please see the [Command-line options][] document for more information.
An example of a [web server][] written with Node.js which responds with
`'Hello, World!'`:

Commands in this document start with `$` or `>` to replicate how they would
appear in a user's terminal. Do not include the `$` and `>` characters. They are
there to show the start of each command.

Lines that don't start with `$` or `>` character show the output of the previous
command.

First, make sure to have downloaded and installed Node.js. See
[Installing Node.js via package manager][] for further install information.
[Installing Node.js][] for further install information.

Now, create an empty project folder called `projects`, then navigate into it.

Expand Down Expand Up @@ -90,5 +83,5 @@ If the browser displays the string `Hello, World!`, that indicates
the server is working.

[Command-line options]: cli.md#options
[Installing Node.js via package manager]: https://nodejs.org/en/download/package-manager/
[Installing Node.js]: https://nodejs.org/en/download
[web server]: http.md
4 changes: 4 additions & 0 deletions lib/internal/crypto/mac.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const {
normalizeHashName,
numBitsToBytes,
truncateToBitLength,
validateKmacKeyLength,
} = require('internal/crypto/util');

const {
Expand Down Expand Up @@ -60,6 +61,9 @@ function normalizeKeyLength(handle, algorithm) {
length = algorithm.length;
}

if (algorithm.name === 'KMAC128' || algorithm.name === 'KMAC256')
validateKmacKeyLength(length);

return { handle, length };
}

Expand Down
14 changes: 14 additions & 0 deletions lib/internal/crypto/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ const {
EVP_PKEY_ML_KEM_1024,
kKeyVariantAES_OCB_128: hasAesOcbMode,
Argon2Job,
getFipsCrypto,
KmacJob,
} = internalBinding('crypto');

const isFips = getFipsCrypto() === 1;

const { getOptionValue } = require('internal/options');

const {
Expand Down Expand Up @@ -423,6 +426,8 @@ const conditionalAlgorithms = {
'Ed448': !process.features.openssl_is_boringssl,
'KMAC128': !!KmacJob,
'KMAC256': !!KmacJob,
'KT128': !isFips,
'KT256': !isFips,
'ML-DSA-44': !!EVP_PKEY_ML_DSA_44,
'ML-DSA-65': !!EVP_PKEY_ML_DSA_65,
'ML-DSA-87': !!EVP_PKEY_ML_DSA_87,
Expand All @@ -435,6 +440,8 @@ const conditionalAlgorithms = {
ArrayPrototypeIncludes(getHashes(), 'sha3-384'),
'SHA3-512': !process.features.openssl_is_boringssl ||
ArrayPrototypeIncludes(getHashes(), 'sha3-512'),
'TurboSHAKE128': !isFips,
'TurboSHAKE256': !isFips,
'X448': !process.features.openssl_is_boringssl,
};

Expand Down Expand Up @@ -579,6 +586,11 @@ function validateMaxBufferLength(data, name, max = kMaxBufferLength) {
}
}

function validateKmacKeyLength(length) {
if ((length < 32 || length % 8) && isFips)
throw lazyDOMException('Invalid key length', 'NotSupportedError');
}

/**
* Converts a bit length to the number of bytes needed to contain it.
* Non-byte lengths are rounded up to the next byte.
Expand Down Expand Up @@ -1097,6 +1109,7 @@ module.exports = {

kNamedCurveAliases,
kSupportedAlgorithms,
isFips,
normalizeAlgorithm,
normalizeHashName,
hasAnyNotIn,
Expand All @@ -1106,6 +1119,7 @@ module.exports = {
jobPromiseThen,
cleanupWebCryptoResult,
prepareWebCryptoResult,
validateKmacKeyLength,
validateMaxBufferLength,
numBitsToBytes,
truncateToBitLength,
Expand Down
51 changes: 34 additions & 17 deletions lib/internal/crypto/webidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const {
StringPrototypeSplit,
StringPrototypeStartsWith,
StringPrototypeToLowerCase,
TypedArrayPrototypeGetLength,
} = primordials;

const {
Expand All @@ -27,8 +26,10 @@ const {
validateMaxBufferLength,
getBufferSourceByteLength,
getBufferSourceBytes,
isFips,
kNamedCurveAliases,
numBitsToBytes,
validateKmacKeyLength,
} = require('internal/crypto/util');
const {
converters: webidl,
Expand Down Expand Up @@ -252,30 +253,39 @@ function validateCShakeOutputLength(V) {
}
}

function bufferSourceEqualsAscii(V, string) {
if (getBufferSourceByteLength(V) !== string.length) return false;

const bytes = getBufferSourceBytes(V);
const length = TypedArrayPrototypeGetLength(bytes);
for (let i = 0; i < length; i++) {
if (bytes[i] !== StringPrototypeCharCodeAt(string, i)) return false;
}
return true;
}
const kCShakeFunctionNames = ['KMAC', 'TupleHash', 'ParallelHash'];

function validateCShakeFunctionName(V) {
if (getBufferSourceByteLength(V) === 0 ||
bufferSourceEqualsAscii(V, 'KMAC') ||
bufferSourceEqualsAscii(V, 'TupleHash') ||
bufferSourceEqualsAscii(V, 'ParallelHash')) {
return;
const length = getBufferSourceByteLength(V);
if (length === 0) return;

if (!isFips) {
const bytes = getBufferSourceBytes(V);
for (let i = 0; i < kCShakeFunctionNames.length; i++) {
const functionName = kCShakeFunctionNames[i];
if (length !== functionName.length) continue;

let j = 0;
for (; j < length; j++) {
if (bytes[j] !== StringPrototypeCharCodeAt(functionName, j)) break;
}
if (j === length) return;
}
}

throw lazyDOMException(
'Unsupported CShakeParams functionName',
'NotSupportedError');
}

function validateCShakeCustomization(V) {
if (isFips && getBufferSourceByteLength(V) !== 0)
throw lazyDOMException(
'Unsupported CShakeParams customization',
'NotSupportedError');
validateMaxBufferLength(V, 'CShakeParams.customization', 512);
}

converters.RsaPssParams = createDictionaryConverter(
'RsaPssParams', [
dictAlgorithm,
Expand Down Expand Up @@ -433,7 +443,7 @@ converters.CShakeParams = createDictionaryConverter(
{
key: 'customization',
converter: converters.BufferSource,
validator: (V, opts) => validateMaxBufferLength(V, 'CShakeParams.customization', 512),
validator: validateCShakeCustomization,
},
],
]);
Expand Down Expand Up @@ -719,6 +729,7 @@ for (let i = 0; i < kKmacDictionaries.length; i++) {
key: 'length',
converter: (V, opts) =>
converters['unsigned long'](V, enforceRangeOptions(opts)),
validator: validateKmacKeyLength,
},
],
]);
Expand All @@ -732,6 +743,12 @@ converters.KmacParams = createDictionaryConverter(
key: 'outputLength',
converter: (V, opts) =>
converters['unsigned long'](V, enforceRangeOptions(opts)),
validator: (V) => {
if ((V === 0 || V % 8) && isFips)
throw lazyDOMException(
'Invalid KmacParams outputLength',
'NotSupportedError');
},
required: true,
},
{
Expand Down
18 changes: 11 additions & 7 deletions lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ function getRunArgs(path, { forceExit,
inspectPort,
testNamePatterns,
testSkipPatterns,
testTagFilterExpressions,
testTagFilters,
only,
hasFiles,
testFiles,
Expand Down Expand Up @@ -224,8 +224,8 @@ function getRunArgs(path, { forceExit,
if (testSkipPatterns != null) {
ArrayPrototypeForEach(testSkipPatterns, (pattern) => ArrayPrototypePush(runArgs, `--test-skip-pattern=${pattern}`));
}
if (testTagFilterExpressions != null) {
ArrayPrototypeForEach(testTagFilterExpressions, (value) => ArrayPrototypePush(runArgs, `--experimental-test-tag-filter=${value}`));
if (testTagFilters != null) {
ArrayPrototypeForEach(testTagFilters, (value) => ArrayPrototypePush(runArgs, `--experimental-test-tag-filter=${value}`));
}
if (only === true) {
ArrayPrototypePush(runArgs, '--test-only');
Expand Down Expand Up @@ -284,6 +284,14 @@ class FileTest extends Test {
this.timeout = null;
}

willBeFilteredByTags() {
// File wrappers have no tags of their own. Tag filtering applies to the
// tests inside the file, which run in a child process (or in-process
// import); filtering the wrapper would prevent the file from running at
// all.
return false;
}

#skipReporting() {
return this.#reportedChildren > 0 && (!this.error || this.error.failureType === kSubtestsFailed);
}
Expand Down Expand Up @@ -864,7 +872,6 @@ function run(options = kEmptyObject) {
});
}

let testTagFilterExpressions = null;
if (testTagFilters != null) {
if (!ArrayIsArray(testTagFilters)) {
testTagFilters = [testTagFilters];
Expand All @@ -876,10 +883,8 @@ function run(options = kEmptyObject) {
testTagFilters = ArrayPrototypeMap(testTagFilters, (value, i) => (
validateAndCanonicalizeTagFilter(value, `options.testTagFilters[${i}]`)
));
testTagFilterExpressions = testTagFilters;
}
}
testTagFilterExpressions ??= options.testTagFilterExpressions;

validateOneOf(isolation, 'options.isolation', ['process', 'none']);
validateBoolean(coverage, 'options.coverage');
Expand Down Expand Up @@ -982,7 +987,6 @@ function run(options = kEmptyObject) {
testNamePatterns,
testSkipPatterns,
testTagFilters,
testTagFilterExpressions,
hasFiles: files != null,
globPatterns,
only,
Expand Down
6 changes: 5 additions & 1 deletion lib/internal/test_runner/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ class Test extends AsyncResource {
}

if (isFilteringByTags) {
this.filteredByTag = !evaluateTagFilters(config.testTagFilters, this.tagSet);
this.filteredByTag = this.willBeFilteredByTags();
if (!this.filteredByTag) {
for (let t = this.parent; t !== null && t.filteredByTag; t = t.parent) {
t.filteredByTag = false;
Expand Down Expand Up @@ -894,6 +894,10 @@ class Test extends AsyncResource {
return false;
}

willBeFilteredByTags() {
return !evaluateTagFilters(this.config.testTagFilters, this.tagSet);
}

/**
* Returns a name of the test prefixed by name of all its ancestors in ascending order, separated by a space
* Ex."grandparent parent test"
Expand Down
18 changes: 5 additions & 13 deletions lib/internal/test_runner/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ function parseCommandLine() {
let testNamePatterns = mapPatternFlagToRegExArray('--test-name-pattern');
let testSkipPatterns = mapPatternFlagToRegExArray('--test-skip-pattern');
let testTagFilters = null;
let testTagFilterExpressions = null;

if (isChildProcessV8) {
kBuiltinReporters.set('v8-serializer', 'internal/test_runner/reporter/v8-serializer');
Expand Down Expand Up @@ -309,19 +308,14 @@ function parseCommandLine() {
const tagFilterFlag = getOptionValue('--experimental-test-tag-filter');
if (tagFilterFlag?.length > 0) {
emitExperimentalWarning('Test tags');
testTagFilterExpressions = tagFilterFlag;
// Validate at parent startup so a malformed flag fails fast,
// independent of isolation mode. Under isolation='process' the
// validated strings go unused at the parent (children re-validate
// and apply the filter); the validation here only surfaces input
// errors early.
const validated = ArrayPrototypeMap(
// File wrappers are exempt from tag filtering, so holding the filters
// in the parent is safe under any isolation mode; under
// isolation='process' the canonical values are re-emitted to the
// child processes, which apply the filter themselves.
testTagFilters = ArrayPrototypeMap(
tagFilterFlag,
(value, i) => validateAndCanonicalizeTagFilter(value, `--experimental-test-tag-filter[${i}]`),
);
if (isolation === 'none') {
testTagFilters = validated;
}
}

if (isolation === 'none') {
Expand Down Expand Up @@ -365,7 +359,6 @@ function parseCommandLine() {
const tagFilterFlag = getOptionValue('--experimental-test-tag-filter');
if (tagFilterFlag?.length > 0) {
emitExperimentalWarning('Test tags');
testTagFilterExpressions = tagFilterFlag;
testTagFilters = ArrayPrototypeMap(
tagFilterFlag,
(value, i) => validateAndCanonicalizeTagFilter(value, `--experimental-test-tag-filter[${i}]`),
Expand Down Expand Up @@ -433,7 +426,6 @@ function parseCommandLine() {
sourceMaps,
testNamePatterns,
testSkipPatterns,
testTagFilterExpressions,
testTagFilters,
timeout,
updateSnapshots,
Expand Down
5 changes: 5 additions & 0 deletions src/crypto/crypto_hash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,11 @@ Maybe<void> CShakeTraits::AdditionalConfig(
CShakeConfig* params) {
Environment* env = Environment::GetCurrent(args);

if (IsFipsEnabled()) {
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env);
return Nothing<void>();
}

CHECK(args[offset]->IsString()); // Algorithm name
Utf8Value algorithm_name(env->isolate(), args[offset]);
std::string_view algorithm_str = algorithm_name.ToStringView();
Expand Down
2 changes: 2 additions & 0 deletions src/crypto/crypto_kmac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ bool DeriveBitsWithCShake(const KmacConfig& params,
const void* key_data,
size_t key_size,
ByteSource* out) {
if (IsFipsEnabled()) return false;

const size_t key_length_bytes = NumBitsToBytes(params.key_length);
if (key_size < key_length_bytes) return false;

Expand Down
10 changes: 10 additions & 0 deletions src/crypto/crypto_turboshake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,11 @@ Maybe<void> TurboShakeTraits::AdditionalConfig(
TurboShakeConfig* params) {
Environment* env = Environment::GetCurrent(args);

if (IsFipsEnabled()) {
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env);
return Nothing<void>();
}

// args[offset + 0] = algorithm name (string)
CHECK(args[offset]->IsString());
Utf8Value algorithm_name(env->isolate(), args[offset]);
Expand Down Expand Up @@ -535,6 +540,11 @@ Maybe<void> KangarooTwelveTraits::AdditionalConfig(
KangarooTwelveConfig* params) {
Environment* env = Environment::GetCurrent(args);

if (IsFipsEnabled()) {
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env);
return Nothing<void>();
}

// args[offset + 0] = algorithm name (string)
CHECK(args[offset]->IsString());
Utf8Value algorithm_name(env->isolate(), args[offset]);
Expand Down
Loading
Loading