FIPS 140-3 certifiable GKI crypto module

The GKI kernel includes a Linux kernel module called fips140.ko that complies with FIPS 140-3 requirements for cryptographic software modules. This module can be submitted for FIPS certification if the product running the GKI kernel requires it.

The following FIPS 140-3 requirements in particular must be fulfilled before the crypto routines may be used:

  • The module must check its own integrity before making cryptographic algorithms available.
  • The module must exercise and verify its approved cryptographic algorithms using known-answer self-tests before making them available.

Why a separate kernel module

FIPS 140-3 validation is based on the idea that once a software or hardware based module has been certified, it is never changed. If changed, it must be recertified. This does not readily match the software development processes in use today, and as a result of this requirement, FIPS software modules are generally designed to be as tightly focused on the cryptographic components as possible, to ensure that changes that are not related to cryptography don't require a reevaluation of the cryptography.

The GKI kernel is intended to be regularly updated during its entire supported lifespan. This makes it infeasible for the whole kernel to be within the FIPS module boundary, as such a module would need to be recertified upon every kernel update. Defining the "FIPS module" to be a subset of the kernel image would mitigate this problem but wouldn't solve it, as the binary contents of the "FIPS module" would still change much more frequently than needed.

Before kernel version 6.1, another consideration was that GKI was compiled with LTO (Link Time Optimization) enabled, since LTO was a prerequisite for Control Flow Integrity which is an important security feature.

Therefore, all code that is covered by the FIPS 140-3 requirements is packaged up into a separate kernel module fips140.ko which only relies on stable interfaces exposed by the GKI kernel source that it was built from. This means that the module can be used with different GKI releases of the same generation, and that it must be updated and resubmitted for certification only if any issues were fixed in the code that is carried by the module itself.

When to use the module

The GKI kernel itself carries code that depends on the crypto routines that are also packaged into the FIPS 140-3 kernel module. Therefore, the built-in crypto routines are not actually moved out of the GKI kernel but rather are copied into the module. When the module is loaded, the built-in crypto routines are deregistered from the Linux CryptoAPI and superseded by the ones carried by the module.

This means that the fips140.ko module is entirely optional, and it only makes sense to deploy it if FIPS 140-3 certification is a requirement. Beyond that, the module provides no additional capabilities, and loading it unnecessarily is only likely to impact boot time, without providing any benefit.

How to deploy the module

The module can be incorporated into the Android build using the following steps:

  • Add the module name to BOARD_VENDOR_RAMDISK_KERNEL_MODULES. This causes the module to be copied to the vendor ramdisk.
  • Add the module name to BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD. This causes the module name to be added to modules.load on the target. modules.load holds the list of modules that are loaded by init when the device boots.

The integrity self check

The FIPS 140-3 kernel module takes the HMAC-SHA256 digest of its own .code and .rodata sections at module load time, and compares it to the digest recorded in the module. This takes place after the Linux module loader has already made the usual modifications such as ELF relocation processing and alternatives patching for CPU errata to those sections. The following additional steps are taken to ensure that the digest can be reproduced correctly:

  • ELF relocations are preserved inside the module so that they can be applied in reverse to the input of the HMAC.
  • The module reverses any code patches that were made by the kernel for Dynamic Shadow Call Stack. Specifically, the module replaces any instructions that push or pop from the shadow call stack with the Pointer Authentication Code (PAC) instructions that were present originally.
  • All other code patching is disabled for the module, including static keys and therefore tracepoints as well as vendor hooks.

The known-answer self tests

Any implemented algorithms that are covered by the FIPS 140-3 requirements must perform a known-answer self test before being used. According to the FIPS 140-3 Implementation Guidance 10.3.A, a single test vector per algorithm using any of the supported key lengths is sufficient for ciphers, as long as both encryption and decryption are tested.

The Linux CryptoAPI has a notion of algorithm priorities, where several implementations (such as one using special crypto instructions, and a fallback for CPUs that don't implement those instructions) of the same algorithm may co-exist. Hence, there is a need to test all implementations of the same algorithm. This is necessary because the Linux CryptoAPI permits the priority based selection to be sidestepped, and for a lower-priority algorithm to be selected instead.

Algorithms included in the module

All algorithms that are included in the FIPS 140-3 module are listed as follows. This applies to the android12-5.10, android13-5.10, android13-5.15, android14-5.15, android14-6.1, and android15-6.6 kernel branches, though differences between kernel versions are noted where appropriate.

Algorithm Implementations Approvable Definition
aes aes-generic, aes-arm64, aes-ce, AES library Yes Plain AES block cipher, with no mode of operation: All key sizes (128 bits, 192 bits, and 256 bits) are supported. All implementations other than the library implementation can be composed with a mode of operation through a template.
cmac(aes) cmac (template), cmac-aes-neon, cmac-aes-ce Yes AES-CMAC: All AES key sizes are supported. The cmac template can be composed with any implementation of aes using cmac(<aes-impl>). The other implementations are standalone.
ecb(aes) ecb (template), ecb-aes-neon, ecb-aes-neonbs, ecb-aes-ce Yes AES-ECB: All AES key sizes are supported. The ecb template can be composed with any implementation of aes using ecb(<aes-impl>). The other implementations are standalone.
cbc(aes) cbc (template), cbc-aes-neon, cbc-aes-neonbs, cbc-aes-ce Yes AES-CBC: All AES key sizes are supported. The cbc template can be composed with any implementation of aes using ctr(<aes-impl>). The other implementations are standalone.
cts(cbc(aes)) cts (template), cts-cbc-aes-neon, cts-cbc-aes-ce Yes AES-CBC-CTS or AES-CBC with ciphertext stealing: The convention used is CS3; the final two ciphertext blocks are swapped unconditionally. All AES key sizes are supported. The cts template can be composed with any implementation of cbc using cts(<cbc(aes)-impl>). The other implementations are standalone.
ctr(aes) ctr (template), ctr-aes-neon, ctr-aes-neonbs, ctr-aes-ce Yes AES-CTR: All AES key sizes are supported. The ctr template can be composed with any implementation of aes using ctr(<aes-impl>). The other implementations are standalone.
xts(aes) xts (template), xts-aes-neon, xts-aes-neonbs, xts-aes-ce Yes AES-XTS: In kernel version 6.1 and lower, all AES key sizes are supported; in kernel version 6.6 and higher, only AES-128 and AES-256 are supported. The xts template can be composed with any implementation of ecb(aes) using xts(<ecb(aes)-impl>). The other implementations are standalone. All implementations implement the weak key check required by FIPS; that is, XTS keys whose first and second halves are equal are rejected.
gcm(aes) gcm (template), gcm-aes-ce No1 AES-GCM: All AES key sizes are supported. Only 96-bit IVs are supported. As with all other AES modes in this module, the caller is responsible for providing the IVs. The gcm template can be composed with any implementations of ctr(aes) and ghash using gcm_base(<ctr(aes)-impl>,<ghash-impl>). The other implementations are standalone.
sha1 sha1-generic, sha1-ce Yes SHA-1 cryptographic hash function
sha224 sha224-generic, sha224-arm64, sha224-ce Yes SHA-224 cryptographic hash function: The code is shared with SHA-256.
sha256 sha256-generic, sha256-arm64, sha256-ce, SHA-256 library Yes SHA-256 cryptographic hash function: A library interface is provided to SHA-256 in addition to the standard CryptoAPI interface. This library interface uses a different implementation.
sha384 sha384-generic, sha384-arm64, sha384-ce Yes SHA-384 cryptographic hash function: The code is shared with SHA-512.
sha512 sha512-generic, sha512-arm64, sha512-ce Yes SHA-512 cryptographic hash function
sha3-224 sha3-224-generic Yes SHA3-224 cryptographic hash function. Only present in kernel version 6.6 and higher.
sha3-256 sha3-256-generic Yes Same as preceding, but with 256-bit digest length (SHA3-256). All digest lengths use the same Keccak implementation.
sha3-384 sha3-384-generic Yes Same as preceding, but with 384-bit digest length (SHA3-384). All digest lengths use the same Keccak implementation.
sha3-512 sha3-512-generic Yes Same as preceding, but with 512-bit digest length (SHA3-512). All digest lengths use the same Keccak implementation.
hmac hmac (template) Yes HMAC (Keyed-Hash Message Authentication Code): The hmac template can be composed with any SHA algorithm or implementation using hmac(<sha-alg>) or hmac(<sha-impl>).
stdrng drbg_pr_hmac_sha1, drbg_pr_hmac_sha256, drbg_pr_hmac_sha384, drbg_pr_hmac_sha512 Yes HMAC_DRBG instantiated with the named hash function and with prediction resistance enabled: Health checks are included. Users of this interface get their own DRBG instances.
stdrng drbg_nopr_hmac_sha1, drbg_nopr_hmac_sha256, drbg_nopr_hmac_sha384, drbg_nopr_hmac_sha512 Yes Same as the drbg_pr_* algorithms, but with prediction resistance disabled. The code is shared with the prediction-resistant variant. In kernel version 5.10, the highest-priority DRBG is drbg_nopr_hmac_sha256. In kernel version 5.15 and higher, it is drbg_pr_hmac_sha512.
jitterentropy_rng jitterentropy_rng No The Jitter RNG, either version 2.2.0 (kernel version 6.1 and lower) or version 3.4.0 (kernel version 6.6 and higher). Users of this interface get their own Jitter RNG instances. They don't reuse the instances the DRBGs use.
xcbc(aes) xcbc-aes-neon, xcbc-aes-ce No
xctr(aes) xctr-aes-neon, xctr-aes-ce No Only present in kernel version 5.15 and higher.
cbcmac(aes) cbcmac-aes-neon, cbcmac-aes-ce No
essiv(cbc(aes),sha256) essiv-cbc-aes-sha256-neon, essiv-cbc-aes-sha256-ce No

Build the module from source

For Android 14 and higher (including android-mainline), build the fips140.ko module from source using the following commands.

  • Build with Bazel:

    tools/bazel run //common:fips140_dist
    
  • Build with build.sh (legacy):

    BUILD_CONFIG=common/build.config.gki.aarch64.fips140 build/build.sh
    

These commands perform a full build including the kernel and the fips140.ko module with the HMAC-SHA256 digest contents embedded in it.

End user guidance

Crypto Officer guidance

To operate the kernel module, the operating system must be restricted to a single operator mode of operation. This is handled automatically by Android using memory management hardware in the processor.

The kernel module cannot be installed separately; it is included as part of the device firmware and loaded automatically on boot. It only operates in an approved mode of operation.

The Crypto Officer can cause the self-tests to be run at any time by restarting the device.

User guidance

The user of the kernel module are other kernel components that need to use cryptographic algorithms. The kernel module does not provide additional logic in the use of the algorithms, and does not store any parameters beyond the time needed to perform a cryptographic operation.

Use of the algorithms for the purposes of FIPS compliance is limited to approved algorithms. To satisfy the FIPS 140-3 "service indicator" requirement, the module provides a function fips140_is_approved_service that indicates whether an algorithm is approved.

Self test errors

In the event of a self test failure, the kernel module causes the kernel to panic and the device does not continue booting. If a reboot of the device does not resolve the issue, the device must boot into recovery mode to correct the problem by re-flashing the device.


  1. It is expected that the module's AES-GCM implementations can be "algorithm approved" but not "module approved". They can be validated, but AES-GCM cannot be considered an approved algorithm from a FIPS module standpoint. This is because the FIPS module requirements for GCM are incompatible with GCM implementations that don't generate their own IVs.