Skip to content

Commit 3cb876b

Browse files
tjuhaszrhphracek
authored andcommitted
Add nodejs fips test and a simple fips app for veriifcation
Add test that verifies that if: Container is in fips mode, node is also using fips mode. Container isnt in fips mode, node also isnt using fips mode. Add simple Fips application which in the context of server verifies: * That FIPS allows the generation of only secure hash algorithms and ciphers. * Should allow: SHA256, AES. Should Fail: MLD, 2Key 3DES.
1 parent 2a9f66d commit 3cb876b

File tree

7 files changed

+208
-1
lines changed

7 files changed

+208
-1
lines changed

test/run

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ test_node_cmd_development_init_wrapper_true
6161
test_init_wrapper_false_development
6262
"
6363

64+
TEST_LIST_FIPS="\
65+
test_nodejs_fips_mode
66+
"
6467
source "${THISDIR}/test-lib.sh"
6568
source "${THISDIR}/test-lib-nodejs.sh"
6669

@@ -160,3 +163,12 @@ evaluate_build_result $? "proxy"
160163
TEST_SET=${TESTS:-$TEST_LIST_HW} ct_run_tests_from_testset "hw"
161164

162165
cleanup
166+
167+
echo "Testing fips mode"
168+
prepare fips
169+
check_prep_result $? fips || exit
170+
echo "Testing the production image build"
171+
run_s2i_fips
172+
evaluate_build_result $? "default"
173+
174+
TEST_SET=${TESTS:-$TEST_LIST_FIPS} ct_run_tests_from_testset "fips"

test/test-fips/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node-echo
2+
=========
3+
4+
node.js echo server, tests fips functionality.

test/test-fips/iisnode.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# For documentation see https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/iisnode.yml
2+
3+
# loggingEnabled: false
4+
# debuggingEnabled: false
5+
# devErrorsEnabled: false
6+
node_env: production
7+
# nodeProcessCountPerApplication: 1
8+
# maxConcurrentRequestsPerProcess: 1024
9+
# maxNamedPipeConnectionRetry: 24
10+
# namedPipeConnectionRetryDelay: 250
11+
# maxNamedPipeConnectionPoolSize: 512
12+
# maxNamedPipePooledConnectionAge: 30000
13+
# asyncCompletionThreadCount: 0
14+
# initialRequestBufferSize: 4096
15+
# maxRequestBufferSize: 65536
16+
watchedFiles: iisnode.yml;node_modules\*;*.js
17+
# uncFileChangesPollingInterval: 5000
18+
# gracefulShutdownTimeout: 60000
19+
# logDirectoryNameSuffix: logs
20+
# debuggerPortRange: 5058-6058
21+
# debuggerPathSegment: debug
22+
# maxLogFileSizeInKB: 128
23+
# appendToExistingLog: false
24+
# logFileFlushInterval: 5000
25+
# flushResponse: false
26+
# enableXFF: false
27+
# promoteServerVars:

test/test-fips/package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "node-echo",
3+
"version": "0.0.1",
4+
"description": "node-echo",
5+
"main": "server.js",
6+
"dependencies": {
7+
},
8+
"devDependencies": {
9+
"nodemon": "*"
10+
},
11+
"engine": {
12+
"node": "*",
13+
"npm": "*"
14+
},
15+
"scripts": {
16+
"dev": "nodemon --ignore node_modules/ server.js",
17+
"start": "node server.js"
18+
},
19+
"repository": {
20+
"type": "git",
21+
"url": "http://github.com/bettiolo/node-echo.git"
22+
},
23+
"keywords": [
24+
"Echo"
25+
],
26+
"author": "Marco Bettiolo <[email protected]>",
27+
"license": "",
28+
"bugs": {
29+
"url": "http://github.com/bettiolo/node-echo/issues"
30+
},
31+
"homepage": "http://apilb.com"
32+
}

test/test-fips/server.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const crypto = require('crypto');
2+
var http = require('http');
3+
var port = process.env.PORT || process.env.port || process.env.OPENSHIFT_NODEJS_PORT || 8080;
4+
var ip = process.env.OPENSHIFT_NODEJS_IP || '0.0.0.0';
5+
var server = http.createServer(function (req, res) {
6+
const fipsMode = getFipsMode();
7+
8+
res.writeHead(200, {'Content-Type': 'text/plain'});
9+
verifySupportedHash(fipsMode);
10+
res.write('Hash generation succesfully verified\n');
11+
verifySupportedCiphers(fipsMode);
12+
res.write('Cipher generation succesfully verified\n');
13+
res.end('\n');
14+
15+
});
16+
server.listen(port);
17+
console.log('Server running on ' + ip + ':' + port);
18+
19+
/*
20+
* Return boolean value
21+
* True if FIPS is enabled
22+
* False if Disabled
23+
*/
24+
function getFipsMode () {
25+
return !!crypto.getFips();
26+
}
27+
28+
/*
29+
* Verify usage of FIPS supported hash algs
30+
* sha256 is FIPS supported
31+
* MLD isn't FIPS supported
32+
*/
33+
function verifySupportedHash(fipsMode) {
34+
try {
35+
const hashSha256 = crypto.createHash('sha256').update('FIPS test').digest('hex');
36+
} catch (e) {
37+
console.error("Error: SHA256 generation should be supported with FIPS.");
38+
exit.process(1);
39+
}
40+
try {
41+
crypto.createHash('md5').update('MD5 test').digest('hex');
42+
if (fipsMode) {
43+
console.error('Error: MD5 generation should not be suscessfull with FIPS enabled.');
44+
exit.process(1);
45+
}
46+
} catch (e) {
47+
if (!fipsMode) {
48+
console.error('Error: MD5 generation should pass without FIPS mode.');
49+
exit.process(1);
50+
}
51+
}
52+
}
53+
54+
/*
55+
* Verify usage of FIPS supported ciphers
56+
* AES is FIPS supported
57+
* 3DES with only two keys isn't FIPS supported
58+
*/
59+
function verifySupportedCiphers(fipsMode) {
60+
try {
61+
const key = crypto.randomBytes(32);
62+
const iv = crypto.randomBytes(16);
63+
const plaintext = 'Test of AES encryption.';
64+
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
65+
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
66+
encrypted += cipher.final('hex');
67+
} catch (e) {
68+
console.error('Error: AES-256 generation should be supported with FIPS');
69+
process.exit(1);
70+
}
71+
try {
72+
const key = crypto.randomBytes(16);
73+
const iv = crypto.randomBytes(8);
74+
crypto.createCipheriv('des-ede-cbc', key, iv);
75+
76+
if (fipsMode) {
77+
console.error("Error: 3DES generation shoud not be succesfull with FIPS mode.")
78+
process.exit(1);
79+
}
80+
} catch (e) {
81+
if (!fipsMode) {
82+
console.error('Error: 3DES generation should be successfull without FIPS mode.',e.message);
83+
process.exit(1);
84+
}
85+
}
86+
87+
88+
}

test/test-fips/web.config

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<configuration>
2+
<system.webServer>
3+
<handlers>
4+
<add name="iisnode" path="server.js" verb="*" modules="iisnode" />
5+
</handlers>
6+
<iisnode loggingEnabled="false" />
7+
8+
<rewrite>
9+
<rules>
10+
<rule name="myapp">
11+
<match url="/*" />
12+
<action type="Rewrite" url="server.js" />
13+
</rule>
14+
</rules>
15+
</rewrite>
16+
</system.webServer>
17+
</configuration>

test/test-lib-nodejs.sh

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ run_s2i_build() {
4545
ct_s2i_build_as_df file://${test_dir}/test-app ${IMAGE_NAME} ${IMAGE_NAME}-testapp ${s2i_args} $(ct_build_s2i_npm_variables) $1
4646
}
4747

48+
run_s2i_fips() {
49+
ct_s2i_build_as_df file://${test_dir}/test-fips${IMAGE_NAME} ${IMAGE_NAME}-testfips ${s2i_args} $(ct_build_s2i_npm_variables) $1
50+
}
51+
4852
run_s2i_build_proxy() {
4953
ct_s2i_build_as_df file://${test_dir}/test-hw ${IMAGE_NAME} ${IMAGE_NAME}-testhw ${s2i_args} $(ct_build_s2i_npm_variables) -e HTTP_PROXY=$1 -e http_proxy=$1 -e HTTPS_PROXY=$2 -e https_proxy=$2
5054
}
@@ -130,7 +134,7 @@ prepare() {
130134
case "$1" in
131135
# TODO: STI build require the application is a valid 'GIT' repository, we
132136
# should remove this restriction in the future when a file:// is used.
133-
app|hw|express-webapp|binary)
137+
app|hw|fips|express-webapp|binary)
134138
pushd "${test_dir}/test-${1}" >/dev/null
135139
prepare_dummy_git_repo
136140
popd >/dev/null
@@ -478,6 +482,29 @@ function test_nodemon_present() {
478482
ct_check_testcase_result "$?"
479483
}
480484

485+
function test_nodejs_fips_mode() {
486+
# Test that nodejs behaves as expected in fips mode
487+
local is_fips_enabled
488+
489+
# Read fips mode from host in case exists
490+
if [[ -f /proc/sys/crypto/fips_enabled ]]; then
491+
is_fips_enabled=$(cat /proc/sys/crypto/fips_enabled)
492+
else
493+
is_fips_enabled="0"
494+
fi
495+
if [[ "$is_fips_enabled" == "0" ]]; then
496+
# FIPS disabled -- crypto.getFips() should return 0
497+
echo "Fips should be disabled"
498+
docker run --rm ${IMAGE_NAME}-testapp /bin/bash -c "node -e 'const crypto = require(\"crypto\"); process.exit(crypto.getFips());'"
499+
ct_check_testcase_result "$?"
500+
else
501+
# FIPS enabled -- crypto.getFips() should return 1
502+
echo "Fips should be enabled"
503+
docker run --rm ${IMAGE_NAME}-testapp /bin/bash -c "! node -e 'const crypto = require(\"crypto\"); process.exit(crypto.getFips());'"
504+
ct_check_testcase_result "$?"
505+
fi
506+
}
507+
481508
function test_npm_cache_cleared() {
482509
# Test that the npm cache has been cleared
483510
cache_loc=$(docker run --rm ${IMAGE_NAME}-testapp /bin/bash -c "npm config get cache")

0 commit comments

Comments
 (0)