Description of problem: An initramfs generated by dracut does not correctly include all required files for cryptographic libraries to behave as they should in FIPS mode. When `fips=1` is present on the kernel command line, RHEL user space should enable FIPS-specific settings and checks, but this does not work for at least OpenSSL and GnuTLS. Specifically, an initramfs generated by dracut, booted with fips=1 on the command line: - Does not list the FIPS provider in `openssl list -providers`, because it does not include `$(pkg-config --variable=modulesdir libcrypto)`, which provides fips.so. Additionally, even with this file present, the lack of an OpenSSL configuration file at `/etc/pki/tls/openssl.cnf` means that the FIPS provider is not automatically enabled. Note that the default `openssl.cnf` also requires `crypto-policies` to be installed. - Fails the GnuTLS integrity checks (which means that the library will refuse to perform any cryptographic operations), because it does not include `%{_libdir}/.gnutls.hmac` This mainly affects initramfs with NetworkManager, because that uses GnuTLS. A similar issue may affect NSS, which keeps its integrity checksums in `%{_libdir}/libfreebl3.chk`, `%{_libdir}/libfreeblpriv3.chk`, and `%{_libdir}/libsoftokn3.chk`. These files must also be present when NSS is included in the initramfs. Version-Release number of selected component (if applicable): 055-45.git20220404.el9_0 How reproducible: Drop into an emergency shell in a dracut initramfs booted with fips=1. Run Steps to Reproduce: 1. openssl list -providers – it should list the OpenSSL FIPS provider, not just the default provider 2. openssl dgst -md5 /bin/sh - should fail if the FIPS provider is correctly used 3. Run any binary that links to libgnutls.so – it must not print "Error in GnuTLS initialization: Error while performing self checks." If you cannot find a binary that does this but have python, you can use: $ python3 >>> from ctypes import * >>> libgnutls = CDLL("/lib64/libgnutls.so.30") Error in GnuTLS initialization: Error while performing self checks. Actual results: Libraries in initramfs will either not work (GnuTLS), or silently perform non-FIPS-approved cryptography (OpenSSL) when booted with `fips=1`. Expected results: Libraries should behave as in FIPS mode and only perform FIPS-validated crypto when booted with `fips=1`. Additional info: This blocks leapp upgrades of systems in FIPS mode (bug 2097003). We need this fixed in 9.0 EUS, 9.1.z and 9.2.z.
See also https://bugzilla.redhat.com/show_bug.cgi?id=2148269, which is related. It seems GnuTLS moved the file recently in response to this problem.
For FIPS compliance, we need the following files in the initramfs when FIPS mode is enabled (i.e., we can probably add them in the FIPS module): - For OpenSSL: - /usr/lib64/ossl-modules/fips.so (or /usr/lib/ossl-modules/fips.so) on all distributions that ship OpenSSL 3. The path to the correct ossl-modules folder can be determined using openssl version -m | sed -E 's/^MODULESDIR: "(.*)"$/\1/', or we can use some auto-detection for libdir. - /etc/pki/tls/openssl.cnf on RHEL/CentOS/Fedora. Due to a downstream patch, FIPS mode will not correctly be enabled if this file does not exist. The path can be determined using openssl version -d | sed -E 's/^OPENSSLDIR: "(.*)"/\1/', but we also just hardcode /etc/pki/tls for Fedora/CentOS/RHEL and not include the configuration file on other distros. - On Ubuntu 20.04 (which still uses OpenSSL 1.1): - /usr/lib/x86_64-linux-gnu/.libssl.so.1.1.hmac - /usr/lib/x86_64-linux-gnu/.libcrypto.so.1.1.hmac - For GnuTLS: - /usr/lib64/.libgnutls.so.*.hmac - /usr/lib64/.libnettle.so.*.hmac - /usr/lib64/.libhogweed.so.*.hmac - /usr/lib64/.libgmp.so.*.hmac (only on Fedora and other distributions, RHEL/CentOS now bundle a copy of libgmp with GnuTLS for FIPS-compliance reasons; you can ignore this fact for dracut as the extra file doesn't hurt) - For libgcrypt: Nothing, everything is included in /usr/lib64/libgcrypt.so.* already :) - For NSS (which we don't want in the initramfs, and thus don't need to support, I'm just listing it here for completeness): - /usr/lib64/libfreebl3.chk - /usr/lib64/libfreeblpriv3.chk - /usr/lib64/libsoftokn3.chk I also checked Ubuntu 22.04 LTS, but that does not have FIPS support at all. So it seems all of that should be covered by your existing code to support the .lib*.hmac files in $libdir, except for NSS (which we don't need), and OpenSSL 3's fips.so and /etc/pki/tls/openssl.cnf.
I'm guessing the reason why I saw GnuTLS fail was https://bugzilla.redhat.com/show_bug.cgi?id=2148269, and has been fixed meanwhile.
So, all of the *hmac are currently correctly installed when needed, we should just add a test for this. But when it comes to working OpenSSL, it is probably not enough to just add fips.so and openssl.cnf. I wrote this small patch https://github.com/lnykryn/dracut/commit/5b2eaf2b7ffa9e0e2436d7a4fa81a8af30f30592 but now: -bash-5.2# openssl list -providers FATAL: Startup failure (dev note: apps_startup()) for openssl 400C3EA1BE7F0000:error:80000002:system library:process_include:No such file or directory:crypto/conf/conf_def.c:805:calling stat(/etc/crypto-policies/back-ends/opensslcnf.config) 400C3EA1BE7F0000:error:07000075:configuration file routines:ssl_module_init:ssl command section empty:crypto/conf/conf_ssl.c:96:name=system_default, value=crypto_policy 400C3EA1BE7F0000:error:0700006D:configuration file routines:module_run:module initialization error:crypto/conf/conf_mod.c:270:module=ssl_conf, value=ssl_module retcode=-1 As you wrote in the first comment, we probably need some files from the crypto-policy package, but I have no idea what should be included and in dracut we don't have "add package" Any ideas?
Btw the test is simple, I've build a small binary linked with one of these libraries [root@localhost ~]# cat dummy.c int main() { return 0; } [root@localhost ~]# gcc -o /usr/bin/dummy dummy.c -lssl -lcrypto wrote a small module [root@localhost ~]# cat /usr/lib/dracut/modules.d/00dummy/module-setup.sh #!/usr/bin/bash check() { return 255 } depends() { return 0 } install() { inst /usr/bin/dummy } build an initrd [root@localhost ~]# dracut -f test.img -a dummy -a fips and check if all files are there
I feared that this might happen, but had hoped that OpenSSL would just ignore the unavailable includes. Unfortunately users could have modified the openssl.cnf file and might have added additional includes, so to avoid all problems, we'd now have to build an OpenSSL configuration file parser that recursively identifies all includes. That's not very desirable. Can we instead ship a minimal openssl.cnf file? $ cat openssl.cnf openssl_conf = openssl_init [openssl_init] providers = provider_sect [provider_sect] default = default_sect [default_sect] activate = 1 Also note that your change should check that the OpenSSL version is >= 3 using openssl version -v, because openssl version -m does not exist on OpenSSL 1.1, fips.so does not exist for OpenSSL 1.1, and the configuration file is not required for OpenSSL 1.x, either.
I've stitched together Lukas's commit with the openssl.cnf: https://github.com/redhat-plumbers/dracut-rhel9/pull/67 Is this a good enough solution?
Yes, this looks good to me!