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