11cb0ef41Sopenharmony_ci// Flags: --expose-internals
21cb0ef41Sopenharmony_ci'use strict';
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciif (!common.hasCrypto)
51cb0ef41Sopenharmony_ci  common.skip('missing crypto');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciconst assert = require('assert');
81cb0ef41Sopenharmony_ciconst spawnSync = require('child_process').spawnSync;
91cb0ef41Sopenharmony_ciconst path = require('path');
101cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
111cb0ef41Sopenharmony_ciconst { internalBinding } = require('internal/test/binding');
121cb0ef41Sopenharmony_ciconst { testFipsCrypto } = internalBinding('crypto');
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciconst FIPS_ENABLED = 1;
151cb0ef41Sopenharmony_ciconst FIPS_DISABLED = 0;
161cb0ef41Sopenharmony_ciconst FIPS_ERROR_STRING2 =
171cb0ef41Sopenharmony_ci  'Error [ERR_CRYPTO_FIPS_FORCED]: Cannot set FIPS mode, it was forced with ' +
181cb0ef41Sopenharmony_ci  '--force-fips at startup.';
191cb0ef41Sopenharmony_ciconst FIPS_UNSUPPORTED_ERROR_STRING = 'fips mode not supported';
201cb0ef41Sopenharmony_ciconst FIPS_ENABLE_ERROR_STRING = 'OpenSSL error when trying to enable FIPS:';
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciconst CNF_FIPS_ON = fixtures.path('openssl_fips_enabled.cnf');
231cb0ef41Sopenharmony_ciconst CNF_FIPS_OFF = fixtures.path('openssl_fips_disabled.cnf');
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_cilet num_children_ok = 0;
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_cifunction sharedOpenSSL() {
281cb0ef41Sopenharmony_ci  return process.config.variables.node_shared_openssl;
291cb0ef41Sopenharmony_ci}
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cifunction testHelper(stream, args, expectedOutput, cmd, env) {
321cb0ef41Sopenharmony_ci  const fullArgs = args.concat(['-e', `console.log(${cmd})`]);
331cb0ef41Sopenharmony_ci  const child = spawnSync(process.execPath, fullArgs, {
341cb0ef41Sopenharmony_ci    cwd: path.dirname(process.execPath),
351cb0ef41Sopenharmony_ci    env: env
361cb0ef41Sopenharmony_ci  });
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  console.error(
391cb0ef41Sopenharmony_ci    `Spawned child [pid:${child.pid}] with cmd '${cmd}' expect %j with args '${
401cb0ef41Sopenharmony_ci      args}' OPENSSL_CONF=%j`, expectedOutput, env.OPENSSL_CONF);
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  function childOk(child) {
431cb0ef41Sopenharmony_ci    console.error(`Child #${++num_children_ok} [pid:${child.pid}] OK.`);
441cb0ef41Sopenharmony_ci  }
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  function responseHandler(buffer, expectedOutput) {
471cb0ef41Sopenharmony_ci    const response = buffer.toString();
481cb0ef41Sopenharmony_ci    assert.notStrictEqual(response.length, 0);
491cb0ef41Sopenharmony_ci    if (FIPS_ENABLED !== expectedOutput && FIPS_DISABLED !== expectedOutput) {
501cb0ef41Sopenharmony_ci      // In the case of expected errors just look for a substring.
511cb0ef41Sopenharmony_ci      assert.ok(response.includes(expectedOutput));
521cb0ef41Sopenharmony_ci    } else {
531cb0ef41Sopenharmony_ci      const getFipsValue = Number(response);
541cb0ef41Sopenharmony_ci      if (!Number.isNaN(getFipsValue))
551cb0ef41Sopenharmony_ci        // Normal path where we expect either FIPS enabled or disabled.
561cb0ef41Sopenharmony_ci        assert.strictEqual(getFipsValue, expectedOutput);
571cb0ef41Sopenharmony_ci    }
581cb0ef41Sopenharmony_ci    childOk(child);
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  responseHandler(child[stream], expectedOutput);
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci// --enable-fips should raise an error if OpenSSL is not FIPS enabled.
651cb0ef41Sopenharmony_citestHelper(
661cb0ef41Sopenharmony_ci  testFipsCrypto() ? 'stdout' : 'stderr',
671cb0ef41Sopenharmony_ci  ['--enable-fips'],
681cb0ef41Sopenharmony_ci  testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING,
691cb0ef41Sopenharmony_ci  'process.versions',
701cb0ef41Sopenharmony_ci  process.env);
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci// --force-fips should raise an error if OpenSSL is not FIPS enabled.
731cb0ef41Sopenharmony_citestHelper(
741cb0ef41Sopenharmony_ci  testFipsCrypto() ? 'stdout' : 'stderr',
751cb0ef41Sopenharmony_ci  ['--force-fips'],
761cb0ef41Sopenharmony_ci  testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING,
771cb0ef41Sopenharmony_ci  'process.versions',
781cb0ef41Sopenharmony_ci  process.env);
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci// By default FIPS should be off in both FIPS and non-FIPS builds
811cb0ef41Sopenharmony_ci// unless Node.js was configured using --shared-openssl in
821cb0ef41Sopenharmony_ci// which case it may be enabled by the system.
831cb0ef41Sopenharmony_ciif (!sharedOpenSSL()) {
841cb0ef41Sopenharmony_ci  testHelper(
851cb0ef41Sopenharmony_ci    'stdout',
861cb0ef41Sopenharmony_ci    [],
871cb0ef41Sopenharmony_ci    FIPS_DISABLED,
881cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
891cb0ef41Sopenharmony_ci    { ...process.env, 'OPENSSL_CONF': ' ' });
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci// This should succeed for both FIPS and non-FIPS builds in combination with
931cb0ef41Sopenharmony_ci// OpenSSL 1.1.1 or OpenSSL 3.0
941cb0ef41Sopenharmony_ciconst test_result = testFipsCrypto();
951cb0ef41Sopenharmony_ciassert.ok(test_result === 1 || test_result === 0);
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci// If Node was configured using --shared-openssl fips support might be
981cb0ef41Sopenharmony_ci// available depending on how OpenSSL was built. If fips support is
991cb0ef41Sopenharmony_ci// available the tests that toggle the fips_mode on/off using the config
1001cb0ef41Sopenharmony_ci// file option will succeed and return 1 instead of 0.
1011cb0ef41Sopenharmony_ci//
1021cb0ef41Sopenharmony_ci// Note that this case is different from when calling the fips setter as the
1031cb0ef41Sopenharmony_ci// configuration file is handled by OpenSSL, so it is not possible for us
1041cb0ef41Sopenharmony_ci// to try to call the fips setter, to try to detect this situation, as
1051cb0ef41Sopenharmony_ci// that would throw an error:
1061cb0ef41Sopenharmony_ci// ("Error: Cannot set FIPS mode in a non-FIPS build.").
1071cb0ef41Sopenharmony_ci// Due to this uncertainty the following tests are skipped when configured
1081cb0ef41Sopenharmony_ci// with --shared-openssl.
1091cb0ef41Sopenharmony_ciif (!sharedOpenSSL() && !common.hasOpenSSL3) {
1101cb0ef41Sopenharmony_ci  // OpenSSL config file should be able to turn on FIPS mode
1111cb0ef41Sopenharmony_ci  testHelper(
1121cb0ef41Sopenharmony_ci    'stdout',
1131cb0ef41Sopenharmony_ci    [`--openssl-config=${CNF_FIPS_ON}`],
1141cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
1151cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1161cb0ef41Sopenharmony_ci    process.env);
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  // OPENSSL_CONF should be able to turn on FIPS mode
1191cb0ef41Sopenharmony_ci  testHelper(
1201cb0ef41Sopenharmony_ci    'stdout',
1211cb0ef41Sopenharmony_ci    [],
1221cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
1231cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1241cb0ef41Sopenharmony_ci    Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  // --openssl-config option should override OPENSSL_CONF
1271cb0ef41Sopenharmony_ci  testHelper(
1281cb0ef41Sopenharmony_ci    'stdout',
1291cb0ef41Sopenharmony_ci    [`--openssl-config=${CNF_FIPS_ON}`],
1301cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
1311cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1321cb0ef41Sopenharmony_ci    Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
1331cb0ef41Sopenharmony_ci}
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci// OpenSSL 3.x has changed the configuration files so the following tests
1361cb0ef41Sopenharmony_ci// will not work as expected with that version.
1371cb0ef41Sopenharmony_ci// TODO(danbev) Revisit these test once FIPS support is available in
1381cb0ef41Sopenharmony_ci// OpenSSL 3.x.
1391cb0ef41Sopenharmony_ciif (!common.hasOpenSSL3) {
1401cb0ef41Sopenharmony_ci  testHelper(
1411cb0ef41Sopenharmony_ci    'stdout',
1421cb0ef41Sopenharmony_ci    [`--openssl-config=${CNF_FIPS_OFF}`],
1431cb0ef41Sopenharmony_ci    FIPS_DISABLED,
1441cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1451cb0ef41Sopenharmony_ci    Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  // --enable-fips should take precedence over OpenSSL config file
1481cb0ef41Sopenharmony_ci  testHelper(
1491cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
1501cb0ef41Sopenharmony_ci    ['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`],
1511cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
1521cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1531cb0ef41Sopenharmony_ci    process.env);
1541cb0ef41Sopenharmony_ci  // --force-fips should take precedence over OpenSSL config file
1551cb0ef41Sopenharmony_ci  testHelper(
1561cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
1571cb0ef41Sopenharmony_ci    ['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`],
1581cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
1591cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1601cb0ef41Sopenharmony_ci    process.env);
1611cb0ef41Sopenharmony_ci  // --enable-fips should turn FIPS mode on
1621cb0ef41Sopenharmony_ci  testHelper(
1631cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
1641cb0ef41Sopenharmony_ci    ['--enable-fips'],
1651cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
1661cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1671cb0ef41Sopenharmony_ci    process.env);
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  // --force-fips should turn FIPS mode on
1701cb0ef41Sopenharmony_ci  testHelper(
1711cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
1721cb0ef41Sopenharmony_ci    ['--force-fips'],
1731cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
1741cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1751cb0ef41Sopenharmony_ci    process.env);
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  // OPENSSL_CONF should _not_ make a difference to --enable-fips
1781cb0ef41Sopenharmony_ci  testHelper(
1791cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
1801cb0ef41Sopenharmony_ci    ['--enable-fips'],
1811cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
1821cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1831cb0ef41Sopenharmony_ci    Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  // Using OPENSSL_CONF should not make a difference to --force-fips
1861cb0ef41Sopenharmony_ci  testHelper(
1871cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
1881cb0ef41Sopenharmony_ci    ['--force-fips'],
1891cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
1901cb0ef41Sopenharmony_ci    'require("crypto").getFips()',
1911cb0ef41Sopenharmony_ci    Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  // setFipsCrypto should be able to turn FIPS mode on
1941cb0ef41Sopenharmony_ci  testHelper(
1951cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
1961cb0ef41Sopenharmony_ci    [],
1971cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
1981cb0ef41Sopenharmony_ci    '(require("crypto").setFips(true),' +
1991cb0ef41Sopenharmony_ci    'require("crypto").getFips())',
2001cb0ef41Sopenharmony_ci    process.env);
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  // setFipsCrypto should be able to turn FIPS mode on and off
2031cb0ef41Sopenharmony_ci  testHelper(
2041cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
2051cb0ef41Sopenharmony_ci    [],
2061cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
2071cb0ef41Sopenharmony_ci    '(require("crypto").setFips(true),' +
2081cb0ef41Sopenharmony_ci    'require("crypto").setFips(false),' +
2091cb0ef41Sopenharmony_ci    'require("crypto").getFips())',
2101cb0ef41Sopenharmony_ci    process.env);
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci  // setFipsCrypto takes precedence over OpenSSL config file, FIPS on
2131cb0ef41Sopenharmony_ci  testHelper(
2141cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
2151cb0ef41Sopenharmony_ci    [`--openssl-config=${CNF_FIPS_OFF}`],
2161cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
2171cb0ef41Sopenharmony_ci    '(require("crypto").setFips(true),' +
2181cb0ef41Sopenharmony_ci    'require("crypto").getFips())',
2191cb0ef41Sopenharmony_ci    process.env);
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  // setFipsCrypto takes precedence over OpenSSL config file, FIPS off
2221cb0ef41Sopenharmony_ci  testHelper(
2231cb0ef41Sopenharmony_ci    'stdout',
2241cb0ef41Sopenharmony_ci    [`--openssl-config=${CNF_FIPS_ON}`],
2251cb0ef41Sopenharmony_ci    FIPS_DISABLED,
2261cb0ef41Sopenharmony_ci    '(require("crypto").setFips(false),' +
2271cb0ef41Sopenharmony_ci    'require("crypto").getFips())',
2281cb0ef41Sopenharmony_ci    process.env);
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci  // --enable-fips does not prevent use of setFipsCrypto API
2311cb0ef41Sopenharmony_ci  testHelper(
2321cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
2331cb0ef41Sopenharmony_ci    ['--enable-fips'],
2341cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
2351cb0ef41Sopenharmony_ci    '(require("crypto").setFips(false),' +
2361cb0ef41Sopenharmony_ci    'require("crypto").getFips())',
2371cb0ef41Sopenharmony_ci    process.env);
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  // --force-fips prevents use of setFipsCrypto API
2401cb0ef41Sopenharmony_ci  testHelper(
2411cb0ef41Sopenharmony_ci    'stderr',
2421cb0ef41Sopenharmony_ci    ['--force-fips'],
2431cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
2441cb0ef41Sopenharmony_ci    'require("crypto").setFips(false)',
2451cb0ef41Sopenharmony_ci    process.env);
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci  // --force-fips makes setFipsCrypto enable a no-op (FIPS stays on)
2481cb0ef41Sopenharmony_ci  testHelper(
2491cb0ef41Sopenharmony_ci    testFipsCrypto() ? 'stdout' : 'stderr',
2501cb0ef41Sopenharmony_ci    ['--force-fips'],
2511cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
2521cb0ef41Sopenharmony_ci    '(require("crypto").setFips(true),' +
2531cb0ef41Sopenharmony_ci    'require("crypto").getFips())',
2541cb0ef41Sopenharmony_ci    process.env);
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci  // --force-fips and --enable-fips order does not matter
2571cb0ef41Sopenharmony_ci  testHelper(
2581cb0ef41Sopenharmony_ci    'stderr',
2591cb0ef41Sopenharmony_ci    ['--force-fips', '--enable-fips'],
2601cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
2611cb0ef41Sopenharmony_ci    'require("crypto").setFips(false)',
2621cb0ef41Sopenharmony_ci    process.env);
2631cb0ef41Sopenharmony_ci
2641cb0ef41Sopenharmony_ci  // --enable-fips and --force-fips order does not matter
2651cb0ef41Sopenharmony_ci  testHelper(
2661cb0ef41Sopenharmony_ci    'stderr',
2671cb0ef41Sopenharmony_ci    ['--enable-fips', '--force-fips'],
2681cb0ef41Sopenharmony_ci    testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
2691cb0ef41Sopenharmony_ci    'require("crypto").setFips(false)',
2701cb0ef41Sopenharmony_ci    process.env);
2711cb0ef41Sopenharmony_ci}
272