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