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
src: fix FIPS init error handling
If `--enable-fips` or `--force-fips` fails to be applied during
`ProcessFipsOptions()`, the node process might exit with
`ExitCode::kNoFailure` because `ERR_GET_REASON(ERR_peek_error())` can
return `0` since `ncrypto::testFipsEnabled()` does not populate the
OpenSSL error queue.

You can likely test this locally by running

    node --enable-fips && echo $?

with the current `node` binary from the main branch if compiled without
support for FIPS.

As confirmed by the `XXX` comment here, which was added three years ago
in commit b697160, even if the error
queue was populated properly, the OpenSSL reason codes are not really
related to the Node.js `ExitCode` enumeration.
  • Loading branch information
tniessen committed May 18, 2025
commit 04b98a7d9dcdab90a75fbdd764ba443bb1cbded4
5 changes: 1 addition & 4 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1175,10 +1175,7 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
}
#endif
if (!crypto::ProcessFipsOptions()) {
// XXX: ERR_GET_REASON does not return something that is
// useful as an exit code at all.
result->exit_code_ =
static_cast<ExitCode>(ERR_GET_REASON(ERR_peek_error()));
result->exit_code_ = ExitCode::kGenericUserError;
result->early_return_ = true;
result->errors_.emplace_back(
"OpenSSL error when trying to enable FIPS:\n" +
Expand Down
29 changes: 28 additions & 1 deletion test/parallel/test-crypto-fips.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ const FIPS_ENABLE_ERROR_STRING = 'OpenSSL error when trying to enable FIPS:';
const CNF_FIPS_ON = fixtures.path('openssl_fips_enabled.cnf');
const CNF_FIPS_OFF = fixtures.path('openssl_fips_disabled.cnf');

const kNoFailure = 0;
const kGenericUserError = 1;

let num_children_ok = 0;

function sharedOpenSSL() {
return process.config.variables.node_shared_openssl;
}

function testHelper(stream, args, expectedOutput, cmd, env) {
function testHelper(stream, args, expectedStatus, expectedOutput, cmd, env) {
const fullArgs = args.concat(['-e', `console.log(${cmd})`]);
const child = spawnSync(process.execPath, fullArgs, {
cwd: path.dirname(process.execPath),
Expand All @@ -56,6 +59,7 @@ function testHelper(stream, args, expectedOutput, cmd, env) {
// Normal path where we expect either FIPS enabled or disabled.
assert.strictEqual(getFipsValue, expectedOutput);
}
assert.strictEqual(child.status, expectedStatus);
childOk(child);
}

Expand All @@ -66,6 +70,7 @@ function testHelper(stream, args, expectedOutput, cmd, env) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--enable-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING,
'process.versions',
process.env);
Expand All @@ -74,6 +79,7 @@ testHelper(
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--force-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING,
'process.versions',
process.env);
Expand All @@ -85,6 +91,7 @@ if (!sharedOpenSSL()) {
testHelper(
'stdout',
[],
kNoFailure,
FIPS_DISABLED,
'require("crypto").getFips()',
{ ...process.env, 'OPENSSL_CONF': ' ' });
Expand All @@ -94,6 +101,7 @@ if (!sharedOpenSSL()) {
testHelper(
'stderr',
[],
kGenericUserError,
'Calling crypto.setFips() is not supported in workers',
'new worker_threads.Worker(\'require("crypto").setFips(true);\', { eval: true })',
process.env);
Expand All @@ -120,6 +128,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) {
testHelper(
'stdout',
[`--openssl-config=${CNF_FIPS_ON}`],
kNoFailure,
testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
'require("crypto").getFips()',
process.env);
Expand All @@ -128,6 +137,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) {
testHelper(
'stdout',
[],
kNoFailure,
testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
'require("crypto").getFips()',
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
Expand All @@ -136,6 +146,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) {
testHelper(
'stdout',
[`--openssl-config=${CNF_FIPS_ON}`],
kNoFailure,
testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
'require("crypto").getFips()',
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
Expand All @@ -149,6 +160,7 @@ if (!hasOpenSSL3) {
testHelper(
'stdout',
[`--openssl-config=${CNF_FIPS_OFF}`],
kNoFailure,
FIPS_DISABLED,
'require("crypto").getFips()',
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
Expand All @@ -157,20 +169,23 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").getFips()',
process.env);
// --force-fips should take precedence over OpenSSL config file
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").getFips()',
process.env);
// --enable-fips should turn FIPS mode on
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--enable-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").getFips()',
process.env);
Expand All @@ -179,6 +194,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--force-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").getFips()',
process.env);
Expand All @@ -187,6 +203,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--enable-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").getFips()',
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
Expand All @@ -195,6 +212,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--force-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").getFips()',
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
Expand All @@ -203,6 +221,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
[],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'(require("crypto").setFips(true),' +
'require("crypto").getFips())',
Expand All @@ -212,6 +231,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
[],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'(require("crypto").setFips(true),' +
'require("crypto").setFips(false),' +
Expand All @@ -222,6 +242,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
[`--openssl-config=${CNF_FIPS_OFF}`],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'(require("crypto").setFips(true),' +
'require("crypto").getFips())',
Expand All @@ -231,6 +252,7 @@ if (!hasOpenSSL3) {
testHelper(
'stdout',
[`--openssl-config=${CNF_FIPS_ON}`],
kNoFailure,
FIPS_DISABLED,
'(require("crypto").setFips(false),' +
'require("crypto").getFips())',
Expand All @@ -240,6 +262,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--enable-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'(require("crypto").setFips(false),' +
'require("crypto").getFips())',
Expand All @@ -249,6 +272,7 @@ if (!hasOpenSSL3) {
testHelper(
'stderr',
['--force-fips'],
kGenericUserError,
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").setFips(false)',
process.env);
Expand All @@ -257,6 +281,7 @@ if (!hasOpenSSL3) {
testHelper(
testFipsCrypto() ? 'stdout' : 'stderr',
['--force-fips'],
testFipsCrypto() ? kNoFailure : kGenericUserError,
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
'(require("crypto").setFips(true),' +
'require("crypto").getFips())',
Expand All @@ -266,6 +291,7 @@ if (!hasOpenSSL3) {
testHelper(
'stderr',
['--force-fips', '--enable-fips'],
kGenericUserError,
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").setFips(false)',
process.env);
Expand All @@ -274,6 +300,7 @@ if (!hasOpenSSL3) {
testHelper(
'stderr',
['--enable-fips', '--force-fips'],
kGenericUserError,
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
'require("crypto").setFips(false)',
process.env);
Expand Down