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