From 5a2b02f8b8996a88d03659695da48cfd4933cd1c Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Mon, 1 Jun 2015 23:49:43 +0200 Subject: [PATCH] crypto: support FIPS mode of OpenSSL Support building and running with FIPS-compliant OpenSSL. The process is following: 1. Download and verify `openssl-fips-x.x.x.tar.gz` from https://www.openssl.org/source/ 2. Extract source to `openssl-fips` folder 3. `cd openssl-fips && ./config fipscanisterbuild --prefix=`pwd`/out` 4. `make -j && make install` 5. Get into io.js checkout folder 6. `./configure --openssl-fips=/path/to/openssl-fips/out` 7. Build io.js with `make -j` Fix: https://github.com/joyent/node/issues/25463 --- common.gypi | 5 +++++ configure | 28 +++++++++++++++++++++++++++- deps/openssl/fips/fipscc | 14 ++++++++++++++ deps/openssl/fips/fipsld | 8 ++++++++ deps/openssl/openssl.gyp | 23 +++++++++++++++++++++++ node.gyp | 4 ++-- src/node_crypto.cc | 10 ++++++++++ 7 files changed, 89 insertions(+), 3 deletions(-) create mode 100755 deps/openssl/fips/fipscc create mode 100755 deps/openssl/fips/fipsld diff --git a/common.gypi b/common.gypi index ea7779ee097a69..4c1b90b29ad2ca 100644 --- a/common.gypi +++ b/common.gypi @@ -38,6 +38,11 @@ 'OBJ_DIR': '<(PRODUCT_DIR)/obj.target', 'V8_BASE': '<(PRODUCT_DIR)/obj.target/deps/v8/tools/gyp/libv8_base.a', }], + ['openssl_fips != ""', { + 'OPENSSL_PRODUCT': 'libcrypto.a', + }, { + 'OPENSSL_PRODUCT': 'libopenssl.a', + }], ['OS=="mac"', { 'clang%': 1, }, { diff --git a/configure b/configure index 5c9b29bf2c2d40..6e031cfe0632f4 100755 --- a/configure +++ b/configure @@ -88,6 +88,11 @@ parser.add_option("--openssl-no-asm", dest="openssl_no_asm", help="Do not build optimized assembly for OpenSSL") +parser.add_option("--openssl-fips", + action="store", + dest="openssl_fips", + help="Build OpenSSL using FIPS canister .o file in supplied folder") + shared_optgroup.add_option('--shared-http-parser', action='store_true', dest='shared_http_parser', @@ -720,6 +725,16 @@ def configure_openssl(o): o['variables']['node_use_openssl'] = b(not options.without_ssl) o['variables']['node_shared_openssl'] = b(options.shared_openssl) o['variables']['openssl_no_asm'] = 1 if options.openssl_no_asm else 0 + if options.openssl_fips: + o['variables']['openssl_fips'] = options.openssl_fips + fips_dir = os.path.join(root_dir, 'deps', 'openssl', 'fips') + fips_ld = os.path.abspath(os.path.join(fips_dir, 'fipsld')) + o['make_global_settings'] = [ + ['LINK', fips_ld + ' <(openssl_fips)/bin/fipsld'], + ] + else: + o['variables']['openssl_fips'] = '' + if options.without_ssl: return @@ -1025,10 +1040,21 @@ configure_fullystatic(output) # move everything else to target_defaults variables = output['variables'] del output['variables'] + +# make_global_settings should be a root level element too +if 'make_global_settings' in output: + make_global_settings = output['make_global_settings'] + del output['make_global_settings'] +else: + make_global_settings = False + output = { 'variables': variables, - 'target_defaults': output + 'target_defaults': output, } +if make_global_settings: + output['make_global_settings'] = make_global_settings + pprint.pprint(output, indent=2) write('config.gypi', do_not_edit + diff --git a/deps/openssl/fips/fipscc b/deps/openssl/fips/fipscc new file mode 100755 index 00000000000000..731c1a659b406c --- /dev/null +++ b/deps/openssl/fips/fipscc @@ -0,0 +1,14 @@ +#!/bin/sh +ARGS= + +while [ "x$1" != "x" ]; do + ARG=$1 + shift + case $ARG in + *fips_premain.c) ARGS="$ARGS -x c $ARG -x none";; + *) ARGS="$ARGS $ARG";; + esac +done + +echo $CXX $ARGS +${CXX} $ARGS diff --git a/deps/openssl/fips/fipsld b/deps/openssl/fips/fipsld new file mode 100755 index 00000000000000..513982aa96ed80 --- /dev/null +++ b/deps/openssl/fips/fipsld @@ -0,0 +1,8 @@ +#!/bin/sh + +# NOTE: Just a wrapper around normal fipsld +FIPSLD=$1 +shift + +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +FIPSLD_CC=$DIR/fipscc $FIPSLD $@ diff --git a/deps/openssl/openssl.gyp b/deps/openssl/openssl.gyp index 5a3dc9b6c74210..d5bb16e5e388f6 100644 --- a/deps/openssl/openssl.gyp +++ b/deps/openssl/openssl.gyp @@ -9,6 +9,7 @@ 'openssl_no_asm%': 0, 'llvm_version%': 0, 'gas_version%': 0, + 'openssl_fips%': 'false', }, 'targets': [ { @@ -21,6 +22,28 @@ ['exclude', 'store/.*$'] ], 'conditions': [ + # FIPS + ['openssl_fips != ""', { + 'defines': [ + 'OPENSSL_FIPS', + ], + 'include_dirs': [ + '<(openssl_fips)/include', + ], + + # Trick fipsld, it expects to see libcrypto.a + 'product_name': 'crypto', + + 'direct_dependent_settings': { + 'defines': [ + 'OPENSSL_FIPS', + ], + 'include_dirs': [ + '<(openssl_fips)/include', + ], + }, + }], + ['openssl_no_asm!=0', { # Disable asm 'defines': [ diff --git a/node.gyp b/node.gyp index de0e47ec2e400d..e098e08906f802 100644 --- a/node.gyp +++ b/node.gyp @@ -233,13 +233,13 @@ [ 'node_target_type!="static_library"', { 'xcode_settings': { 'OTHER_LDFLAGS': [ - '-Wl,-force_load,<(PRODUCT_DIR)/libopenssl.a', + '-Wl,-force_load,<(PRODUCT_DIR)/<(OPENSSL_PRODUCT)', ], }, 'conditions': [ ['OS in "linux freebsd"', { 'ldflags': [ - '-Wl,--whole-archive <(PRODUCT_DIR)/libopenssl.a', + '-Wl,--whole-archive <(PRODUCT_DIR)/<(OPENSSL_PRODUCT)', '-Wl,--no-whole-archive', ], }], diff --git a/src/node_crypto.cc b/src/node_crypto.cc index e2c478a510be84..ba2e804f0e78e6 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -5071,6 +5071,16 @@ void InitCryptoOnce() { CRYPTO_set_locking_callback(crypto_lock_cb); CRYPTO_THREADID_set_callback(crypto_threadid_cb); +#ifdef OPENSSL_FIPS + if (!FIPS_mode_set(1)) { + int r; + r = ERR_get_error(); + fprintf(stderr, "openssl fips failed: %s\n", ERR_error_string(r, NULL)); + UNREACHABLE(); + } +#endif /* BUD_FIPS_ENABLED */ + + // Turn off compression. Saves memory and protects against CRIME attacks. #if !defined(OPENSSL_NO_COMP) #if OPENSSL_VERSION_NUMBER < 0x00908000L