[PATCH v2 15/19] crypto: fips140: add module integrity self-check

Jay Wang
2026-04-18T00:24:36Z

Add verify_integrity() function to perform HMAC-SHA256 self verification
of this standalone crypto module against pre-computed hash. This integrity
self-check is required by FIPS 140-3.

This patch is picked from Vegard Nossum <vegard.nossum@oracle.com> with
minor modifications.

Co-developed-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Jay Wang <wanjay@amazon.com>
---
crypto/fips140/Kconfig | 2 ++
crypto/fips140/fips140-module.c | 52 +++++++++++++++++++++++++++++++++
crypto/fips140/fips140-module.h | 4 +++
3 files changed, 58 insertions(+)

diff --git a/crypto/fips140/Kconfig b/crypto/fips140/Kconfig
index 7d8997aa10945..85d2c99579549 100644
--- a/crypto/fips140/Kconfig
+++ b/crypto/fips140/Kconfig
@@ -2,6 +2,8 @@ config CRYPTO_FIPS140_EXTMOD
bool "FIPS 140 compliant algorithms as a kernel module"
depends on CRYPTO && (X86_64 || ARM64) && MODULES
select CRYPTO_FIPS
+ select CRYPTO_SHA256
+ select CRYPTO_HMAC
help
This option enables building a kernel module that contains
copies of crypto algorithms that are built in a way that
diff --git a/crypto/fips140/fips140-module.c b/crypto/fips140/fips140-module.c
index 8767d98baacd9..1e68c509d2db0 100644
--- a/crypto/fips140/fips140-module.c
+++ b/crypto/fips140/fips140-module.c
@@ -16,6 +16,54 @@

#define CRYPTO_INTERNAL "CRYPTO_INTERNAL"

+static const u8 fips140_integ_hmac_key[] = CONFIG_CRYPTO_FIPS140_HMAC_KEY;
+
+static int verify_integrity(void)
+{
+ extern const u8 *_binary_crypto_ko_start;
+ extern const u8 *_binary_crypto_ko_end;
+ extern const u8 *_binary_crypto_hmac_start;
+
+ struct crypto_shash *tfm;
+ SHASH_DESC_ON_STACK(desc, tfm);
+ u8 digest[SHA256_DIGEST_SIZE];
+ int err;
+
+ tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+ if (IS_ERR(tfm))
+ panic("FIPS 140: failed to allocate hmac tfm (%ld)\n", PTR_ERR(tfm));
+
+ desc->tfm = tfm;
+
+ err = crypto_shash_setkey(tfm, fips140_integ_hmac_key, sizeof(fips140_integ_hmac_key) - 1);
+ if (err)
+ panic("FIPS 140: crypto_shash_setkey() failed: %d\n", err);
+
+ err = crypto_shash_init(desc);
+ if (err)
+ panic("FIPS 140: crypto_shash_init() failed: %d\n", err);
+
+ err = crypto_shash_update(desc, _binary_crypto_ko_start, _binary_crypto_ko_end - _binary_crypto_ko_start);
+ if (err)
+ panic("FIPS 140: crypto_shash_update() failed: %d\n", err);
+
+ err = crypto_shash_final(desc, digest);
+ if (err)
+ panic("FIPS 140: crypto_shash_final() failed: %d\n", err);
+
+ shash_desc_zero(desc);
+
+ if (memcmp(digest, _binary_crypto_hmac_start, sizeof(digest)))
+ panic("FIPS 140: failed integrity check\n");
+
+ pr_info("FIPS 140: integrity verification passed\n");
+
+ crypto_free_shash(tfm);
+ memzero_explicit(digest, sizeof(digest));
+
+ return 0;
+}
+
/*
* Run FIPS module initcalls level by level, synchronizing with the
* kernel's initcall progression.
@@ -85,6 +133,10 @@ static int __init fips140_init(void)
pr_info("loading " FIPS140_MODULE_NAME "\n");

run_initcalls();
+
+ if (fips_enabled){
+ verify_integrity(); /* Panics if integrity check fails */
+ }
fips140_mark_module_level_complete(3);
return 0;
}
diff --git a/crypto/fips140/fips140-module.h b/crypto/fips140/fips140-module.h
index e95dac8eeda9e..b8968d54800ec 100644
--- a/crypto/fips140/fips140-module.h
+++ b/crypto/fips140/fips140-module.h
@@ -9,9 +9,13 @@
#include <linux/module.h>
#include <linux/crypto.h>
#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/sha2.h>
#include <linux/init.h>
+#include <linux/string.h>
#include <linux/atomic.h>
#include <linux/wait.h>
+#include <linux/fips.h>

/* FIPS140 synchronization between kernel and module */
extern atomic_t fips140_kernel_level_complete;
--
2.47.3