Updated 2025 Sept 09:
UEK8 has been submitted to the labs for FIPS 140-3 certification. As part of that effort, we’ve also sent out an RFC of the patchset below — take a look at it here, and if you support this work, please provide feedback! lore.kernel.org [RFC] crypto: support for a standalone FIPS 140 module
***
Currently, UEK8 is not FIPS 140-3 certified. This blog discusses the work we’re doing to achieve that certification, and is intended for developers familiar with the Linux kernel and with the FIPS standard. If you’re here to check if UEK8 is FIPS 140-3 certified, please start here.
You may have spotted the fips branch in our UEK repo; I’ve gotten a few questions about collaborating on improving the state of FIPS certifications in Linux. Yay! github.com/oracle/linux-uek/tree/fips/uek8-draft is our development branch for building out the FIPS 140-3 module which will be submitted to the certification labs. It’s a work in progress, and it’s nearing completion.
Background on FIPS
FIPS is the Federal Information Protection Standard, maintained by the US National Institute of Standards and Technology (NIST). FIPS certifies the binary implementation of specific approved cryptographic algorithms as part of the Cryptographic Module Validation Program (CMVP). In practice, the certification includes both the source and the binary, though the end result is a certification attached to the binary output.
Having FIPS 140-3 certifications is a requirement for running in many secure contexts. We consider it a priority to get UEK8’s Cryptographic Module Boundary certified for FIPS 140-3. Note that the word “module” in Cryptographic Module Boundary is not the same as a ‘kernel module’, despite the presence of a fips140.ko kernel module. That distinction is important to understanding what we’re about to describe.
Shrink the Cryptographic Module Boundary
In a typical certification, the FIPS Cryptographic Module Boundary is the whole of the compiled Linux kernel (vmlinuz); with these changes the Cryptographic Module Boundary is exclusively the provided fips140.ko kernel module and metadata. To be clear: it is technically correct to include the whole of the Linux kernel in the FIPS boundary, and this is what we and other vendors are doing with our current FIPS certifications. When this happens, though, the contents of the FIPS boundary change every time the kernel is recompiled, and customers have to rely on vendor attestation to say that they are FIPS 140-3 certified. This is how FIPS certification works in UEK7, and we’re trying to improve this for UEK8.
This work proposes to create a stable kernel crypto API that can be encapsulated within a single fips140.ko kernel module. This fips140.ko module will stand alone and will be certified separately from the rest of the kernel, though it would still be tied to the KABI-stabilized code in UEK8. The fips140.ko module would also represent the Cryptographic Module Boundary for the purpose of the certification.
Our original goal was to establish a FIPS kernel module (fips140.ko) which could load into any Linux kernel – and so far, we have not succeeded. We tried a number of different approaches, but kept running into the usual KABI changes that foil most third-party modules. Combined with the strict requirements about FIPS binary module compliance, we decided to reduce our ambitions somewhat to producing a fips140 kernel module that could work against a single KABI-stabilized longterm-stable tree, like UEK8. We also explored the Android FIPS implementation, and ultimately decided on the approach described here.
Contents of the Cryptographic Module Boundary
In our proposed solution, we embed the fips140.ko module within the vmlinux file after compilation, along with its own HMAC digest. That HMAC is then checked when the fips140 module is loaded using the HMAC algorithm from within the fips140.ko itself. FIPS mode is selectable at boot time, using either the certified module or the standard in-kernel crypto binaries.
The module boundary is defined as a kernel module (ELF file) fips140.ko, and its HMAC digest, fips140.hmac. The kernel module, fips140.ko, is built as an external (out-of-tree) module and embeds an archive (fips140-archive.a) containing further kernel modules implementing various cryptographic algorithms (e.g. sha1_generic.ko), algorithm self-tests, and parts of the kernel’s cryptographic API. fips140.ko and fips140.hmac are stored inside vmlinux using plain byte arrays. This way, the module and its digest do not need to be stored on or loaded from a filesystem, but are loaded into memory alongside the rest of the kernel by the boot loader. They can also easily be extracted from the kernel image for verification purposes.
There were any number of complications with aspects like kernel-module signature verification; our solution gets around some of those by providing an “early load” path for trusted kernel modules to be loaded. This also gets around the bootstrap problem of having the kernel module signature-checker code as part of the FIPS boundary.
fips140.ko for Upstream
This work is public and open source, but it’s not part of the mainline kernel. There is plenty of FIPS-related code in mainline which is enabled when booting with fips=1 but the code cannot be cleanly separated out from the rest of the kernel. We are planning a mailing list submission and we don’t necessarily expect these patches to be merged any time soon, but at least we can kick off a discussion around modularized FIPS support upstream. We also think this could be a good first step towards delineating the mainline kernel crypto API from the rest of the kernel, to facilitate projects like this in the future.
We’re planning to share a more detailed technical writeup of how this all works together once we’re further along in the certification process, but for now we hope other vendors will take note of this work – if it works for us, it should work for you, so give it a try and let us know! greg.marsden@oracle.com
