Skip to content

Commit 0d7644f

Browse files
danbevmhdawson
authored andcommitted
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. PR-URL: #38633 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Michael Dawson <midawson@redhat.com>
1 parent 35b445d commit 0d7644f

File tree

6 files changed

+157
-4
lines changed

6 files changed

+157
-4
lines changed

BUILDING.md

+129-1
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,135 @@ as `deps/icu` (You'll have: `deps/icu/source/...`)
759759

760760
## Building Node.js with FIPS-compliant OpenSSL
761761

762-
The current version of Node.js does not support FIPS.
762+
The current version of Node.js does not support FIPS when statically linking
763+
(the default) with OpenSSL 1.1.1 but for dynamically linking it is possible
764+
to enable FIPS using the configuration flag `--openssl-is-fips`.
765+
766+
### Configuring and building quictls/openssl for FIPS
767+
768+
For quictls/openssl 3.0 it is possible to enable FIPS when dynamically linking.
769+
Node.js currently uses openssl-3.0.0+quic which can be configured as
770+
follows:
771+
```console
772+
$ git clone git@github.com:quictls/openssl.git
773+
$ cd openssl
774+
$ ./config --prefix=/path/to/install/dir/ shared enable-fips linux-x86_64
775+
```
776+
This can be compiled and installed using the following commands:
777+
```console
778+
$ make -j8
779+
$ make install_ssldirs
780+
$ make install_fips
781+
```
782+
783+
After the FIPS module and configuration file have been installed by the above
784+
instructions we also need to update `/path/to/install/dir/ssl/openssl.cnf` to
785+
use the generated FIPS configuration file (`fipsmodule.cnf`):
786+
```text
787+
.include fipsmodule.cnf
788+
789+
# List of providers to load
790+
[provider_sect]
791+
default = default_sect
792+
# The fips section name should match the section name inside the
793+
# included /path/to/install/dir/ssl/fipsmodule.cnf.
794+
fips = fips_sect
795+
796+
[default_sect]
797+
activate = 1
798+
```
799+
800+
In the above case OpenSSL is not installed in the default location so two
801+
environment variables need to be set, `OPENSSL_CONF`, and `OPENSSL_MODULES`
802+
which should point to the OpenSSL configuration file and the directory where
803+
OpenSSL modules are located:
804+
```console
805+
$ export OPENSSL_CONF=/path/to/install/dir/ssl/openssl.cnf
806+
$ export OPENSSL_MODULES=/path/to/install/dir/lib/ossl-modules
807+
```
808+
809+
Node.js can then be configured to enable FIPS:
810+
```console
811+
$ ./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
812+
$ export LD_LIBRARY_PATH=/path/to/install/dir/lib
813+
$ make -j8
814+
```
815+
816+
Verify the produced executable:
817+
```console
818+
$ ldd ./node
819+
linux-vdso.so.1 (0x00007ffd7917b000)
820+
libcrypto.so.81.3 => /path/to/install/dir/lib/libcrypto.so.81.3 (0x00007fd911321000)
821+
libssl.so.81.3 => /path/to/install/dir/lib/libssl.so.81.3 (0x00007fd91125e000)
822+
libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007fd911232000)
823+
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fd911039000)
824+
libm.so.6 => /usr/lib64/libm.so.6 (0x00007fd910ef3000)
825+
libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007fd910ed9000)
826+
libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00007fd910eb5000)
827+
libc.so.6 => /usr/lib64/libc.so.6 (0x00007fd910cec000)
828+
/lib64/ld-linux-x86-64.so.2 (0x00007fd9117f2000)
829+
```
830+
If the `ldd` command says that `libcrypto` cannot be found one needs to set
831+
`LD_LIBRARY_PATH` to point to the directory used above for
832+
`--shared-openssl-libpath` (see previous step).
833+
834+
Verify the OpenSSL version:
835+
```console
836+
$ ./node -p process.versions.openssl
837+
3.0.0-alpha16+quic
838+
```
839+
840+
Verify that FIPS is available:
841+
```console
842+
$ ./node -p 'process.config.variables.openssl_is_fips'
843+
true
844+
$ ./node --enable-fips -p 'crypto.getFips()'
845+
1
846+
```
847+
848+
FIPS support can then be enable via the OpenSSL configuration file or
849+
using `--enable-fips` or `--force-fips` command line options to the Node.js
850+
executable. See sections
851+
[Enabling FIPS using Node.js options](#enabling-fips-using-node.js-options) and
852+
[Enabling FIPS using OpenSSL config](#enabling-fips-using-openssl-config) below.
853+
854+
### Enabling FIPS using Node.js options
855+
This is done using one of the Node.js options `--enable-fips` or
856+
`--force-fips`, for example:
857+
```console
858+
$ node --enable-fips -p 'crypto.getFips()'
859+
```
860+
861+
### Enabling FIPS using OpenSSL config
862+
This example show that using OpenSSL's configuration file, FIPS can be enabled
863+
without specifying the `--enable-fips` or `--force-fips` options by setting
864+
`default_properties = fips=yes` in the FIPS configuration file. See
865+
[link](https://github.com/openssl/openssl/blob/master/README-FIPS.md#loading-the-fips-module-at-the-same-time-as-other-providers)
866+
for details.
867+
868+
For this to work the OpenSSL configuration file (default openssl.cnf) needs to
869+
be updated. The following shows an example:
870+
```console
871+
openssl_conf = openssl_init
872+
873+
.include /path/to/install/dir/ssl/fipsmodule.cnf
874+
875+
[openssl_init]
876+
providers = prov
877+
alg_section = algorithm_sect
878+
879+
[prov]
880+
fips = fips_sect
881+
default = default_sect
882+
883+
[default_sect]
884+
activate = 1
885+
886+
[algorithm_sect]
887+
default_properties = fips=yes
888+
```
889+
After this change Node.js can be run without the `--enable-fips` or `--force-fips`
890+
options.
763891

764892
## Building Node.js with external core modules
765893

common.gypi

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
'v8_base': '<(PRODUCT_DIR)/obj.target/tools/v8_gypfiles/libv8_snapshot.a',
100100
}],
101101
['openssl_fips != ""', {
102-
'openssl_product': '<(STATIC_LIB_PREFIX)crypto<(STATIC_LIB_SUFFIX)',
102+
'openssl_product': '<(STATIC_LIB_PREFIX)openssl<(STATIC_LIB_SUFFIX)',
103103
}, {
104104
'openssl_product': '<(STATIC_LIB_PREFIX)openssl<(STATIC_LIB_SUFFIX)',
105105
}],

configure.py

+6
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,12 @@ def without_ssl_error(option):
14561456
if options.openssl_fips or options.openssl_fips == '':
14571457
error('FIPS is not supported in this version of Node.js')
14581458

1459+
if options.openssl_is_fips and not options.shared_openssl:
1460+
error('--openssl-is-fips is only available with --shared-openssl')
1461+
1462+
if options.openssl_is_fips:
1463+
o['defines'] += ['OPENSSL_FIPS']
1464+
14591465
if options.shared_openssl:
14601466
variables['openssl_quic'] = b(getsharedopensslhasquic.get_has_quic(options.__dict__['shared_openssl_includes']))
14611467

src/crypto/crypto_util.cc

+15
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

1515
#include "math.h"
1616

17+
#ifdef OPENSSL_FIPS
18+
#if OPENSSL_VERSION_MAJOR >= 3
19+
#include "openssl/provider.h"
20+
#endif
21+
#endif
22+
1723
namespace node {
1824

1925
using v8::ArrayBuffer;
@@ -197,7 +203,16 @@ void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
197203

198204
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args) {
199205
#ifdef OPENSSL_FIPS
206+
#if OPENSSL_VERSION_MAJOR >= 3
207+
OSSL_PROVIDER* fips_provider = nullptr;
208+
if (OSSL_PROVIDER_available(nullptr, "fips")) {
209+
fips_provider = OSSL_PROVIDER_load(nullptr, "fips");
210+
}
211+
const auto enabled = fips_provider == nullptr ? 0 :
212+
OSSL_PROVIDER_self_test(fips_provider) ? 1 : 0;
213+
#else
200214
const auto enabled = FIPS_selftest() ? 1 : 0;
215+
#endif
201216
#else // OPENSSL_FIPS
202217
const auto enabled = 0;
203218
#endif // OPENSSL_FIPS

src/crypto/crypto_util.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#endif // !OPENSSL_NO_ENGINE
2525
// The FIPS-related functions are only available
2626
// when the OpenSSL itself was compiled with FIPS support.
27-
#ifdef OPENSSL_FIPS
27+
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_MAJOR < 3
2828
# include <openssl/fips.h>
2929
#endif // OPENSSL_FIPS
3030

test/parallel/test-crypto-fips.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ testHelper(
6666
'require("crypto").getFips()',
6767
{ ...process.env, 'OPENSSL_CONF': '' });
6868

69+
// This should succeed for both FIPS and non-FIPS builds in combination with
70+
// OpenSSL 1.1.1 or OpenSSL 3.0
71+
const test_result = testFipsCrypto();
72+
assert.ok(test_result === 1 || test_result === 0);
6973

7074
// If Node was configured using --shared-openssl fips support might be
7175
// available depending on how OpenSSL was built. If fips support is
@@ -79,7 +83,7 @@ testHelper(
7983
// ("Error: Cannot set FIPS mode in a non-FIPS build.").
8084
// Due to this uncertainty the following tests are skipped when configured
8185
// with --shared-openssl.
82-
if (!sharedOpenSSL()) {
86+
if (!sharedOpenSSL() && !common.hasOpenSSL3) {
8387
// OpenSSL config file should be able to turn on FIPS mode
8488
testHelper(
8589
'stdout',

0 commit comments

Comments
 (0)