• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Flags: --expose-internals
2'use strict';
3const common = require('../common');
4if (!common.hasCrypto)
5  common.skip('missing crypto');
6
7const assert = require('assert');
8const spawnSync = require('child_process').spawnSync;
9const path = require('path');
10const fixtures = require('../common/fixtures');
11const { internalBinding } = require('internal/test/binding');
12const { testFipsCrypto } = internalBinding('crypto');
13
14const FIPS_ENABLED = 1;
15const FIPS_DISABLED = 0;
16const FIPS_ERROR_STRING2 =
17  'Error [ERR_CRYPTO_FIPS_FORCED]: Cannot set FIPS mode, it was forced with ' +
18  '--force-fips at startup.';
19const FIPS_UNSUPPORTED_ERROR_STRING = 'fips mode not supported';
20
21const CNF_FIPS_ON = fixtures.path('openssl_fips_enabled.cnf');
22const CNF_FIPS_OFF = fixtures.path('openssl_fips_disabled.cnf');
23
24let num_children_ok = 0;
25
26function sharedOpenSSL() {
27  return process.config.variables.node_shared_openssl;
28}
29
30function testHelper(stream, args, expectedOutput, cmd, env) {
31  const fullArgs = args.concat(['-e', `console.log(${cmd})`]);
32  const child = spawnSync(process.execPath, fullArgs, {
33    cwd: path.dirname(process.execPath),
34    env: env
35  });
36
37  console.error(
38    `Spawned child [pid:${child.pid}] with cmd '${cmd}' expect %j with args '${
39      args}' OPENSSL_CONF=%j`, expectedOutput, env.OPENSSL_CONF);
40
41  function childOk(child) {
42    console.error(`Child #${++num_children_ok} [pid:${child.pid}] OK.`);
43  }
44
45  function responseHandler(buffer, expectedOutput) {
46    const response = buffer.toString();
47    assert.notStrictEqual(response.length, 0);
48    if (FIPS_ENABLED !== expectedOutput && FIPS_DISABLED !== expectedOutput) {
49      // In the case of expected errors just look for a substring.
50      assert.ok(response.includes(expectedOutput));
51    } else {
52      // Normal path where we expect either FIPS enabled or disabled.
53      assert.strictEqual(Number(response), expectedOutput);
54    }
55    childOk(child);
56  }
57
58  responseHandler(child[stream], expectedOutput);
59}
60
61// By default FIPS should be off in both FIPS and non-FIPS builds.
62testHelper(
63  'stdout',
64  [],
65  FIPS_DISABLED,
66  'require("crypto").getFips()',
67  { ...process.env, 'OPENSSL_CONF': ' ' });
68
69// --enable-fips should turn FIPS mode on
70testHelper(
71  testFipsCrypto() ? 'stdout' : 'stderr',
72  ['--enable-fips'],
73  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
74  'require("crypto").getFips()',
75  process.env);
76
77// --force-fips should turn FIPS mode on
78testHelper(
79  testFipsCrypto() ? 'stdout' : 'stderr',
80  ['--force-fips'],
81  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
82  'require("crypto").getFips()',
83  process.env);
84
85// If Node was configured using --shared-openssl fips support might be
86// available depending on how OpenSSL was built. If fips support is
87// available the tests that toggle the fips_mode on/off using the config
88// file option will succeed and return 1 instead of 0.
89//
90// Note that this case is different from when calling the fips setter as the
91// configuration file is handled by OpenSSL, so it is not possible for us
92// to try to call the fips setter, to try to detect this situation, as
93// that would throw an error:
94// ("Error: Cannot set FIPS mode in a non-FIPS build.").
95// Due to this uncertainty the following tests are skipped when configured
96// with --shared-openssl.
97if (!sharedOpenSSL()) {
98  // OpenSSL config file should be able to turn on FIPS mode
99  testHelper(
100    'stdout',
101    [`--openssl-config=${CNF_FIPS_ON}`],
102    testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
103    'require("crypto").getFips()',
104    process.env);
105
106  // OPENSSL_CONF should be able to turn on FIPS mode
107  testHelper(
108    'stdout',
109    [],
110    testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
111    'require("crypto").getFips()',
112    Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
113
114  // --openssl-config option should override OPENSSL_CONF
115  testHelper(
116    'stdout',
117    [`--openssl-config=${CNF_FIPS_ON}`],
118    testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED,
119    'require("crypto").getFips()',
120    Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
121}
122
123testHelper(
124  'stdout',
125  [`--openssl-config=${CNF_FIPS_OFF}`],
126  FIPS_DISABLED,
127  'require("crypto").getFips()',
128  Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
129
130// --enable-fips should take precedence over OpenSSL config file
131testHelper(
132  testFipsCrypto() ? 'stdout' : 'stderr',
133  ['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`],
134  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
135  'require("crypto").getFips()',
136  process.env);
137
138// OPENSSL_CONF should _not_ make a difference to --enable-fips
139testHelper(
140  testFipsCrypto() ? 'stdout' : 'stderr',
141  ['--enable-fips'],
142  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
143  'require("crypto").getFips()',
144  Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
145
146// --force-fips should take precedence over OpenSSL config file
147testHelper(
148  testFipsCrypto() ? 'stdout' : 'stderr',
149  ['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`],
150  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
151  'require("crypto").getFips()',
152  process.env);
153
154// Using OPENSSL_CONF should not make a difference to --force-fips
155testHelper(
156  testFipsCrypto() ? 'stdout' : 'stderr',
157  ['--force-fips'],
158  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
159  'require("crypto").getFips()',
160  Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
161
162// setFipsCrypto should be able to turn FIPS mode on
163testHelper(
164  testFipsCrypto() ? 'stdout' : 'stderr',
165  [],
166  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
167  '(require("crypto").setFips(true),' +
168  'require("crypto").getFips())',
169  process.env);
170
171// setFipsCrypto should be able to turn FIPS mode on and off
172testHelper(
173  testFipsCrypto() ? 'stdout' : 'stderr',
174  [],
175  testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
176  '(require("crypto").setFips(true),' +
177  'require("crypto").setFips(false),' +
178  'require("crypto").getFips())',
179  process.env);
180
181// setFipsCrypto takes precedence over OpenSSL config file, FIPS on
182testHelper(
183  testFipsCrypto() ? 'stdout' : 'stderr',
184  [`--openssl-config=${CNF_FIPS_OFF}`],
185  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
186  '(require("crypto").setFips(true),' +
187  'require("crypto").getFips())',
188  process.env);
189
190// setFipsCrypto takes precedence over OpenSSL config file, FIPS off
191testHelper(
192  'stdout',
193  [`--openssl-config=${CNF_FIPS_ON}`],
194  FIPS_DISABLED,
195  '(require("crypto").setFips(false),' +
196  'require("crypto").getFips())',
197  process.env);
198
199// --enable-fips does not prevent use of setFipsCrypto API
200testHelper(
201  testFipsCrypto() ? 'stdout' : 'stderr',
202  ['--enable-fips'],
203  testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
204  '(require("crypto").setFips(false),' +
205  'require("crypto").getFips())',
206  process.env);
207
208// --force-fips prevents use of setFipsCrypto API
209testHelper(
210  'stderr',
211  ['--force-fips'],
212  testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
213  'require("crypto").setFips(false)',
214  process.env);
215
216// --force-fips makes setFipsCrypto enable a no-op (FIPS stays on)
217testHelper(
218  testFipsCrypto() ? 'stdout' : 'stderr',
219  ['--force-fips'],
220  testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
221  '(require("crypto").setFips(true),' +
222  'require("crypto").getFips())',
223  process.env);
224
225// --force-fips and --enable-fips order does not matter
226testHelper(
227  'stderr',
228  ['--force-fips', '--enable-fips'],
229  testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
230  'require("crypto").setFips(false)',
231  process.env);
232
233// --enable-fips and --force-fips order does not matter
234testHelper(
235  'stderr',
236  ['--enable-fips', '--force-fips'],
237  testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
238  'require("crypto").setFips(false)',
239  process.env);
240