Friday, December 26, 2014

Nodejs FIPS

NodeJS FIPS

NodeJS is using OpenSSL for all its encryption and decryption.  NodeJS distribution is build with OpenSSL without FIPS support and it's statically linked. To enable FIPS for NodeJS, we'll have to recompile NodeJS.

OpenSSL FIPS Object Module

Download OpenSSL FIPS module (in time of writing openssl-fips-2.0.4.tar.gz) http://www.openssl.org/source/
Install the module following the steps in OpenSSL FIPS Object Module pdf http://www.openssl.org/docs/fips/UserGuide-2.0.pdf:

For Linux

$ ./config
$ make
$make install
Note! To ensure FIPS complience, NO configuration options are allowed!
Download OpenSSL (in time of writing openssl-1.0.1e.tar.gz) http://www.openssl.org/source/http://www.openssl.org/source/
Install OpenSSL with the following commands:
$ ./config fips shared -fPIC
$ make
$ make install
Note! ./config fips is a required option in FIPS Object Module security policy, any following options, like shared -fPIC, are optional.

For Windows

Install Visual Studio 2010

Download Visual Studio 2010 choose Visual Studio 2010 All-in-One ISO.
Note! if you get a linker error, you'll have to install Windows SDK 7.1 before installing Visual Studio 2010.

Install NASM

Download NASM 2.10.09
To compile:
nmake /f Mkfiles/msvc.mak
Add NASM to PATH env variable.

Install Active Perl

Download and install Active Perl

Compile OpenSSL FIPS Object Module

"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat"
cd c:\openssl-fips-2.0.5
set PROCESSOR_ARCHITECTURE=x86
ms\do_fips
ms\do_nasm
nmake -f ms\ntdll.mak test
nmake -f ms\ntdll.mak install
the files will be copied to C:\usr\local\ssl\fips-2.0. (make sure FIPS_DIR environment is not set if the files are copied to somewhere else)

Compile OpenSSL

"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat"
cd c:\openssl-1.0.1e
perl Configure VC-WIN32 fips --with-fipslibdir=C:\usr\local\ssl\fips-2.0\lib --with-fipsdir=C:\usr\local\ssl\fips-2.0
ms\do_nasm
nmake -f ms\ntdll.mak clean
nmake -f ms\ntdll.mak install
the files will be copied to c:\usr\local\ssl.

to verify if FIPS is compiled correctly for openssl

cd /usr/local/ssl/bin
./openssl version   <- you should see fips in the output.
echo "Some test text" > foo.txt
./openssl bf -salt -in foo.txt
(supply a password x2 )
It should echo out the crypted text.
Repeat the test, but export OPENSSL_FIPS=1 first.
Openssl should fail, claiming that its not allowed to use that algorithm. This means fips mode is working correctly.

NodeJS

Download NodeJS

download source code from http://nodejs.org/download/ or clone from NodeJS repository
git clone https://github.com/joyent/node
git checkout v0.10.21-release

Modify source code to add FIPS support

For Linux

edit src/node.cc in project node
add crypto.h at line 78
#if HAVE_OPENSSL
#include "node_crypto.h"
#include "crypto.h"
#endif
add FIPS_mode_set at line 2299 (after adding openssl/crypto.h)
void SetupProcessObject(...)
{
...
#if HAVE_OPENSSL
...
if(!FIPS_mode_set(1)){
  fprintf(stderr,"OpenSSL shared library does not support FIPS mode");
  exit(1);
}
...
#endif
...
}
edit ../../src/object.cc in project v8_base
comment out assert check at line 4698
//ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name);
a PR is submitted to NodeJS to add FIPS, https://github.com/joyent/node/pull/6380

For Windows

Download and install python 2.7.6
python configure --dest-cpu=ia32 --shared-openssl --shared-openssl-libname=libeay32,ssleay32 --shared-openssl-includes=c:\usr\local\ssl\include
  1. open node.sln in Visual Studio 2010
  2. change configuration to Release
  3. open project properties for mksnapshot.ia32 and remove libeasy32.lib and ssleay32.dll from linker input's additional dependencies
  4. open project properties for node and add c:\usr\local\ssl\lib to linker general's additional library directories
  1. edit src/node.cc
add crypto.h at line 78
#if HAVE_OPENSSL
#include "node_crypto.h"
#include "openssl/crypto.h"
#endif
add FIPS_mode_set at line 2299 (after adding openssl/crypto.h)
void SetupProcessObject(...)
{
...
#if HAVE_OPENSSL
...
if(!FIPS_mode_set(1)){
  fprintf(stderr,"OpenSSL shared library does not support FIPS mode");
  exit(1);
}
...
#endif
...
}
  1. edit ../../src/object.cc in project v8_base
comment out assert check at line 4698
//ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name);

compile NodeJS

For Linux

./configure --shared-openssl --shared-openssl-libpath=/usr/local/ssl/lib --shared-openssl-includes=/usr/local/ssl/include/openssl
make clean
make
make test
  • /usr/local/ssl is the default output path for fips enabled openssl. to compliant with FIPS, you should not modify the location of the output directory when building openssl but you can copy the files to another location after compiling it.
to verify if the node is linked to the correct library
cd out/Release
ldd ./node
libssl.so.1.0.0 & libcrypto.so.1.0.0 should be linked to the one in /usr/local/ssl/lib.

For Windows

open node.sln in Visual Studio 2010
build solution
copy libeasy32.dll and ssleay32.dll from c:\usr\local\ssl\bin to ...\node.js
copy Release\node.exe to ...\node.js

verify if node has FIPS compiled correctly

test_fips.js
#!/usr/bin/env node
'use strict';
var crypto = require('crypto');
var cipher = crypto.createCipher('bf','12345');
var encrypted = cipher.update('encrypt this very long string' 'utf8''base64');
encrypted = encrypted + cipher.final('base64');
var decipher = crypto.createDecipher('bf','12345');
var decrypted = decipher.update(encrypted, 'base64''utf8');
decrypted = decrypted + decipher.final('utf8');
console.log( 'encrypted: ' + encrypted );
console.log( 'decrypted: ' + decrypted );
execute test_fips.js, it should fail.
./node test_fips.js