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/fips140-module.c | 52 +++++++++++++++++++++++++++++++++
 crypto/fips140/fips140-module.h |  4 +++
 2 files changed, 56 insertions(+)

diff --git a/crypto/fips140/fips140-module.c b/crypto/fips140/fips140-module.c
index e0e669ba1b5e..3bc8865567cb 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;
+}
+
 static int __init run_initcalls(void)
 {
        typedef int (*initcall_t)(void);
@@ -68,6 +116,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(2);
     return 0;
 }
diff --git a/crypto/fips140/fips140-module.h b/crypto/fips140/fips140-module.h
index e95dac8eeda9..b8968d54800e 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