From d6649514bf83eefcb43a144a47203db39ab735a8 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 26 Apr 2021 05:52:16 +0200 Subject: [PATCH 1/4] build,src,test,doc: enable FIPS for OpenSSL 3.0 This commit enables FIPS when Node.js is dynamically linking against quictls/openssl-3.0. BUILDING.md has been updated with instructions to configure and build quictls/openssl 3.0.0-alpha-15 and includes a couple of work-arounds which I believe are fixed in alpha-16 and can be removed when alpha-16 is available. The information might be a little too detailed/verbose but I thought it would be helpful to at least initially include all the steps. --- BUILDING.md | 151 +++++++++++++++++++++++++++++- common.gypi | 2 +- configure.py | 6 ++ src/crypto/crypto_util.cc | 13 +++ test/parallel/test-crypto-fips.js | 6 +- 5 files changed, 175 insertions(+), 3 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 973c87b73ea1a5..6b160fab748fb4 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -759,7 +759,156 @@ as `deps/icu` (You'll have: `deps/icu/source/...`) ## Building Node.js with FIPS-compliant OpenSSL -The current version of Node.js does not support FIPS. +The current version of Node.js does not support FIPS when statically linking +(the default) with OpenSSL 1.1.1 but for dynamically linking it is possible +to enable FIPS using the configuration flag `--openssl-is-fips`. + +### Configuring and Building quictls/openssl for FIPS + +For quictls/openssl 3.0 it is possible to enable FIPS when dynamically linking. +Node.js currently uses openssl-3.0.0-alpha15+quic which can be configured as +follows: +```console +$ git clone git@github.com:quictls/openssl.git +$ cd openssl +$ ./config -Werror --strict-warnings --debug --prefix=/path/to/install/dir/ shared enable-fips linux-x86_64 +``` +This can be compiled using: +```console +$ make -j8 +$ make install_ssldirs +``` +Next set the `PATH` environment variable to point to the `openssl` executable +in the `apps` directory: +```console +$ export PATH=./apps:$PATH +``` +Now that should be enough to run the target `install_fips` but there seems to +be an error with alpha-15 in regards to this target (this should be fixed in +alpha-16). This can be worked around by removing the last option of the openssl +fipsinstall command so that is looks like this: + +```console +install_fips: install_sw + @$(ECHO) "*** Installing FIPS module configuration" + @$(ECHO) "fipsinstall $(DESTDIR)$(MODULESDIR)/$(FIPSMODULENAME).cnf" + @openssl fipsinstall -module $(DESTDIR)$(MODULESDIR)/$(FIPSMODULENAME) \ + -out $(DESTDIR)$(MODULESDIR)/$(FIPSMODULENAME).cnf +``` + +With those changes it should be possible to run the `install_fips` target: +```console +$ make install_fips +``` + +After the FIPS module and configuration file have been installed by the above +instructions we also need to update `/path/to/install/dir/ssl/openssl.cnf` to +use the generated FIPS configuration file (`fips.so.cnf`): +```text +.include /path/to/install/dir/lib/ossl-modules/fips.so.cnf + +# List of providers to load +[provider_sect] +default = default_sect +# The fips section name should match the section name inside the +# included fips.so.cnf. +fips = fips_sect + +[default_sect] +activate = 1 +``` + +In the above case OpenSSL is not installed in the default location so two +environment variables need to be set, `OPENSSL_CONF`, and `OPENSSL_MODULES` +which should point to the OpenSSL configuration file and the directory where +OpenSSL modules are located: +```console +$ export OPENSSL_CONF=/path/to/install/dir/ssl/openssl.cnf +$ export OPENSSL_MODULES=/path/to/install/dir/lib/ossl-modules +``` + +Node.js can then be configured to enable FIPS: +```console +$ ./configure --shared-openssl --shared-openssl-libpath=/path/to/install/dir/lib --shared-openssl-includes=/path/to/install/dir/include --shared-openssl-libname=crypto,ssl --openssl-is-fips +$ export LD_LIBRARY_PATH=/path/to/install/dir/lib +$ make -j8 +``` + +Verify the produced executable: +```console +$ ldd ./node + linux-vdso.so.1 (0x00007ffd7917b000) + libcrypto.so.81.3 => /path/to/install/dir/lib/libcrypto.so.81.3 (0x00007fd911321000) + libssl.so.81.3 => /path/to/install/dir/lib/libssl.so.81.3 (0x00007fd91125e000) + libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007fd911232000) + libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fd911039000) + libm.so.6 => /usr/lib64/libm.so.6 (0x00007fd910ef3000) + libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007fd910ed9000) + libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00007fd910eb5000) + libc.so.6 => /usr/lib64/libc.so.6 (0x00007fd910cec000) + /lib64/ld-linux-x86-64.so.2 (0x00007fd9117f2000) +``` +If the `ldd` command says that `libcrypto` cannot be found one needs to set +`LD_LIBRARY_PATH` to point to the directory used above for +`--shared-openssl-libpath` (see previous step). + +Verify the OpenSSL version: +```console +$ ./node -p process.versions.openssl +3.0.0-alpha15+quic +``` + +Verify that FIPS is available: +```console +$ ./node -p 'process.config.variables.openssl_is_fips' +true +$ ./node --enable-fips -p 'crypto.getFips()' +1 +``` + +FIPS support can then be enable via the OpenSSL configuration file or +using `--enable-fips` or `--force-fips` command line options to the Node.js +executable. See sections +[Enabling FIPS using Node.js options](#enabling-fips-using-node.js-options) and +[Enabling FIPS using OpenSSL config](#enabling-fips-using-openssl-config) below. + +### Enabling FIPS using Node.js options +This is done using one of the Node.js options `--enable-fips` or +`--force-fips`, for example: +```console +$ node --enable-fips -p 'crypto.getFips()' +``` + +### Enabling FIPS using OpenSSL config +This example show that using OpenSSL's configuration file, FIPS can be enabled +without specifying the `--enable-fips` or `--force-fips` options by setting +`default_properties = fips=yes` in the FIPS configuration file. See +[link](https://github.com/openssl/openssl/blob/master/README-FIPS.md#loading-the-fips-module-at-the-same-time-as-other-providers) +for details. + +For this to work the OpenSSL configuration file (default openssl.cnf) needs to +be updated. The following shows an example: +```console +openssl_conf = openssl_init + +.include /path/to/install/dir/lib/ossl-modules/fips.so.cnf + +[openssl_init] +providers = prov +alg_section = algorithm_sect + +[prov] +fips = fips_sect +default = default_sect + +[default_sect] +activate = 1 + +[algorithm_sect] +default_properties = fips=yes +``` +After this change Node.js can be run without the `--enable-fips` or `--force-fips` +options. ## Building Node.js with external core modules diff --git a/common.gypi b/common.gypi index 75d4b692e9b62b..4bc75c7c41c6dd 100644 --- a/common.gypi +++ b/common.gypi @@ -99,7 +99,7 @@ 'v8_base': '<(PRODUCT_DIR)/obj.target/tools/v8_gypfiles/libv8_snapshot.a', }], ['openssl_fips != ""', { - 'openssl_product': '<(STATIC_LIB_PREFIX)crypto<(STATIC_LIB_SUFFIX)', + 'openssl_product': '<(STATIC_LIB_PREFIX)openssl<(STATIC_LIB_SUFFIX)', }, { 'openssl_product': '<(STATIC_LIB_PREFIX)openssl<(STATIC_LIB_SUFFIX)', }], diff --git a/configure.py b/configure.py index b877319841e1e2..5564dfc30859ee 100755 --- a/configure.py +++ b/configure.py @@ -1451,6 +1451,12 @@ def without_ssl_error(option): if options.openssl_fips or options.openssl_fips == '': error('FIPS is not supported in this version of Node.js') + if options.openssl_is_fips and not options.shared_openssl: + error('--openssl-is-fips is only available with --shared-openssl') + + if options.openssl_is_fips: + o['defines'] += ['OPENSSL_FIPS'] + if options.shared_openssl: variables['openssl_quic'] = b(getsharedopensslhasquic.get_has_quic(options.__dict__['shared_openssl_includes'])) diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 9c35a7cabbf551..054c31305eff2c 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -14,6 +14,10 @@ #include "math.h" +#ifdef OPENSSL_FIPS +#include "openssl/provider.h" +#endif + namespace node { using v8::ArrayBuffer; @@ -197,7 +201,16 @@ void SetFipsCrypto(const FunctionCallbackInfo& args) { void TestFipsCrypto(const v8::FunctionCallbackInfo& args) { #ifdef OPENSSL_FIPS +#if OPENSSL_VERSION_MAJOR >= 3 + OSSL_PROVIDER* fips_provider = nullptr; + if (OSSL_PROVIDER_available(nullptr, "fips")) { + fips_provider = OSSL_PROVIDER_load(nullptr, "fips"); + } + const auto enabled = fips_provider == nullptr ? 0 : + OSSL_PROVIDER_self_test(fips_provider) ? 1 : 0; +#else const auto enabled = FIPS_selftest() ? 1 : 0; +#endif #else // OPENSSL_FIPS const auto enabled = 0; #endif // OPENSSL_FIPS diff --git a/test/parallel/test-crypto-fips.js b/test/parallel/test-crypto-fips.js index 204951514a8ede..b6e70b62be68b9 100644 --- a/test/parallel/test-crypto-fips.js +++ b/test/parallel/test-crypto-fips.js @@ -66,6 +66,10 @@ testHelper( 'require("crypto").getFips()', { ...process.env, 'OPENSSL_CONF': '' }); +// This should succeed for both FIPS and non-FIPS builds in combination with +// OpenSSL 1.1.1 or OpenSSL 3.0 +const test_result = testFipsCrypto(); +assert.ok(test_result === 1 || test_result === 0); // If Node was configured using --shared-openssl fips support might be // available depending on how OpenSSL was built. If fips support is @@ -79,7 +83,7 @@ testHelper( // ("Error: Cannot set FIPS mode in a non-FIPS build."). // Due to this uncertainty the following tests are skipped when configured // with --shared-openssl. -if (!sharedOpenSSL()) { +if (!sharedOpenSSL() && !common.hasOpenSSL3) { // OpenSSL config file should be able to turn on FIPS mode testHelper( 'stdout', From 3695a5c4e52b756168dded55df4ad9c894cddaef Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 11 May 2021 18:29:37 +0200 Subject: [PATCH 2/4] squash! build,src,test,doc: enable FIPS for OpenSSL 3.0 Add macro guard to OpenSSL 3.0 include. --- src/crypto/crypto_util.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 054c31305eff2c..0d533ce42531d1 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -15,8 +15,10 @@ #include "math.h" #ifdef OPENSSL_FIPS +#if OPENSSL_VERSION_MAJOR >= 3 #include "openssl/provider.h" #endif +#endif namespace node { From 21b475c68deac45b9673427c29694acee4f772ff Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 12 May 2021 07:26:32 +0200 Subject: [PATCH 3/4] squash! build,src,test,doc: enable FIPS for OpenSSL 3.0 Update to 3.0.0-alpha-16 --- BUILDING.md | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 6b160fab748fb4..64cdfc278de377 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -766,52 +766,31 @@ to enable FIPS using the configuration flag `--openssl-is-fips`. ### Configuring and Building quictls/openssl for FIPS For quictls/openssl 3.0 it is possible to enable FIPS when dynamically linking. -Node.js currently uses openssl-3.0.0-alpha15+quic which can be configured as +Node.js currently uses openssl-3.0.0+quic which can be configured as follows: ```console $ git clone git@github.com:quictls/openssl.git $ cd openssl $ ./config -Werror --strict-warnings --debug --prefix=/path/to/install/dir/ shared enable-fips linux-x86_64 ``` -This can be compiled using: +This can be compiled and installed using the following commands: ```console $ make -j8 $ make install_ssldirs -``` -Next set the `PATH` environment variable to point to the `openssl` executable -in the `apps` directory: -```console -$ export PATH=./apps:$PATH -``` -Now that should be enough to run the target `install_fips` but there seems to -be an error with alpha-15 in regards to this target (this should be fixed in -alpha-16). This can be worked around by removing the last option of the openssl -fipsinstall command so that is looks like this: - -```console -install_fips: install_sw - @$(ECHO) "*** Installing FIPS module configuration" - @$(ECHO) "fipsinstall $(DESTDIR)$(MODULESDIR)/$(FIPSMODULENAME).cnf" - @openssl fipsinstall -module $(DESTDIR)$(MODULESDIR)/$(FIPSMODULENAME) \ - -out $(DESTDIR)$(MODULESDIR)/$(FIPSMODULENAME).cnf -``` - -With those changes it should be possible to run the `install_fips` target: -```console $ make install_fips ``` After the FIPS module and configuration file have been installed by the above instructions we also need to update `/path/to/install/dir/ssl/openssl.cnf` to -use the generated FIPS configuration file (`fips.so.cnf`): +use the generated FIPS configuration file (`fipsmodule.cnf`): ```text -.include /path/to/install/dir/lib/ossl-modules/fips.so.cnf +.include fipsmodule.cnf # List of providers to load [provider_sect] default = default_sect # The fips section name should match the section name inside the -# included fips.so.cnf. +# included fipsmodule.cnf. fips = fips_sect [default_sect] From ccb63c06ea29be40b17a9afc6a73884ace7906c9 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 12 May 2021 19:26:03 +0200 Subject: [PATCH 4/4] squash! build,src,test,doc: enable FIPS for OpenSSL 3.0 --- BUILDING.md | 30 +++++++++++++++--------------- src/crypto/crypto_util.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 64cdfc278de377..6ebe84f6e1aad5 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -763,7 +763,7 @@ The current version of Node.js does not support FIPS when statically linking (the default) with OpenSSL 1.1.1 but for dynamically linking it is possible to enable FIPS using the configuration flag `--openssl-is-fips`. -### Configuring and Building quictls/openssl for FIPS +### Configuring and building quictls/openssl for FIPS For quictls/openssl 3.0 it is possible to enable FIPS when dynamically linking. Node.js currently uses openssl-3.0.0+quic which can be configured as @@ -771,7 +771,7 @@ follows: ```console $ git clone git@github.com:quictls/openssl.git $ cd openssl -$ ./config -Werror --strict-warnings --debug --prefix=/path/to/install/dir/ shared enable-fips linux-x86_64 +$ ./config --prefix=/path/to/install/dir/ shared enable-fips linux-x86_64 ``` This can be compiled and installed using the following commands: ```console @@ -790,7 +790,7 @@ use the generated FIPS configuration file (`fipsmodule.cnf`): [provider_sect] default = default_sect # The fips section name should match the section name inside the -# included fipsmodule.cnf. +# included /path/to/install/dir/ssl/fipsmodule.cnf. fips = fips_sect [default_sect] @@ -816,16 +816,16 @@ $ make -j8 Verify the produced executable: ```console $ ldd ./node - linux-vdso.so.1 (0x00007ffd7917b000) - libcrypto.so.81.3 => /path/to/install/dir/lib/libcrypto.so.81.3 (0x00007fd911321000) - libssl.so.81.3 => /path/to/install/dir/lib/libssl.so.81.3 (0x00007fd91125e000) - libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007fd911232000) - libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fd911039000) - libm.so.6 => /usr/lib64/libm.so.6 (0x00007fd910ef3000) - libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007fd910ed9000) - libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00007fd910eb5000) - libc.so.6 => /usr/lib64/libc.so.6 (0x00007fd910cec000) - /lib64/ld-linux-x86-64.so.2 (0x00007fd9117f2000) + linux-vdso.so.1 (0x00007ffd7917b000) + libcrypto.so.81.3 => /path/to/install/dir/lib/libcrypto.so.81.3 (0x00007fd911321000) + libssl.so.81.3 => /path/to/install/dir/lib/libssl.so.81.3 (0x00007fd91125e000) + libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007fd911232000) + libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fd911039000) + libm.so.6 => /usr/lib64/libm.so.6 (0x00007fd910ef3000) + libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007fd910ed9000) + libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00007fd910eb5000) + libc.so.6 => /usr/lib64/libc.so.6 (0x00007fd910cec000) + /lib64/ld-linux-x86-64.so.2 (0x00007fd9117f2000) ``` If the `ldd` command says that `libcrypto` cannot be found one needs to set `LD_LIBRARY_PATH` to point to the directory used above for @@ -834,7 +834,7 @@ If the `ldd` command says that `libcrypto` cannot be found one needs to set Verify the OpenSSL version: ```console $ ./node -p process.versions.openssl -3.0.0-alpha15+quic +3.0.0-alpha16+quic ``` Verify that FIPS is available: @@ -870,7 +870,7 @@ be updated. The following shows an example: ```console openssl_conf = openssl_init -.include /path/to/install/dir/lib/ossl-modules/fips.so.cnf +.include /path/to/install/dir/ssl/fipsmodule.cnf [openssl_init] providers = prov diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h index 27bb6310b884d1..f2f61aa4518581 100644 --- a/src/crypto/crypto_util.h +++ b/src/crypto/crypto_util.h @@ -24,7 +24,7 @@ #endif // !OPENSSL_NO_ENGINE // The FIPS-related functions are only available // when the OpenSSL itself was compiled with FIPS support. -#ifdef OPENSSL_FIPS +#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_MAJOR < 3 # include #endif // OPENSSL_FIPS