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 <[email protected]> with
minor modifications.

Co-developed-by: Vegard Nossum <[email protected]>
Signed-off-by: Jay Wang <[email protected]>
---
 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


Reply via email to