Allow the integrity test to be run on demand.
Change-Id: If45a98427516c5a26f2048adb8f8d0415417dcf8
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51987
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/crypto_test.cc b/crypto/crypto_test.cc
index 228aaf2..caccba5 100644
--- a/crypto/crypto_test.cc
+++ b/crypto/crypto_test.cc
@@ -152,3 +152,9 @@
EXPECT_FALSE(FIPS_query_algorithm_status("FakeEncrypt"));
EXPECT_FALSE(FIPS_query_algorithm_status(""));
}
+
+#if defined(BORINGSSL_FIPS) && !defined(OPENSSL_ASAN)
+TEST(Crypto, OnDemandIntegrityTest) {
+ BORINGSSL_integrity_test();
+}
+#endif
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index 1219bc7..faff6c4 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -169,6 +169,23 @@
#if !defined(OPENSSL_ASAN)
// Integrity tests cannot run under ASAN because it involves reading the full
// .text section, which triggers the global-buffer overflow detection.
+ if (!BORINGSSL_integrity_test()) {
+ goto err;
+ }
+#endif // OPENSSL_ASAN
+
+ if (!boringssl_self_test_startup()) {
+ goto err;
+ }
+
+ return;
+
+err:
+ BORINGSSL_FIPS_abort();
+}
+
+#if !defined(OPENSSL_ASAN)
+int BORINGSSL_integrity_test(void) {
const uint8_t *const start = BORINGSSL_bcm_text_start;
const uint8_t *const end = BORINGSSL_bcm_text_end;
@@ -198,14 +215,14 @@
const EVP_MD *const kHashFunction = EVP_sha256();
if (!boringssl_self_test_sha256() ||
!boringssl_self_test_hmac_sha256()) {
- goto err;
+ return 0;
}
#else
uint8_t result[SHA512_DIGEST_LENGTH];
const EVP_MD *const kHashFunction = EVP_sha512();
if (!boringssl_self_test_sha512() ||
!boringssl_self_test_hmac_sha256()) {
- goto err;
+ return 0;
}
#endif
@@ -216,7 +233,7 @@
if (!HMAC_Init_ex(&hmac_ctx, kHMACKey, sizeof(kHMACKey), kHashFunction,
NULL /* no ENGINE */)) {
fprintf(stderr, "HMAC_Init_ex failed.\n");
- goto err;
+ return 0;
}
BORINGSSL_maybe_set_module_text_permissions(PROT_READ | PROT_EXEC);
@@ -236,7 +253,7 @@
if (!HMAC_Final(&hmac_ctx, result, &result_len) ||
result_len != sizeof(result)) {
fprintf(stderr, "HMAC failed.\n");
- goto err;
+ return 0;
}
HMAC_CTX_cleanse(&hmac_ctx); // FIPS 140-3, AS05.10.
@@ -244,22 +261,14 @@
if (!check_test(expected, result, sizeof(result), "FIPS integrity test")) {
#if !defined(BORINGSSL_FIPS_BREAK_TESTS)
- goto err;
+ return 0;
#endif
}
OPENSSL_cleanse(result, sizeof(result)); // FIPS 140-3, AS05.10.
-#endif // OPENSSL_ASAN
-
- if (!boringssl_self_test_startup()) {
- goto err;
- }
-
- return;
-
-err:
- BORINGSSL_FIPS_abort();
+ return 1;
}
+#endif // OPENSSL_ASAN
void BORINGSSL_FIPS_abort(void) {
for (;;) {
diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h
index 15db776..117b347 100644
--- a/include/openssl/crypto.h
+++ b/include/openssl/crypto.h
@@ -59,6 +59,12 @@
// success and zero on error.
OPENSSL_EXPORT int BORINGSSL_self_test(void);
+// BORINGSSL_integrity_test triggers the module's integrity test where the code
+// and data of the module is matched against a hash injected at build time. It
+// returns one on success or zero if there's a mismatch. This function only
+// exists if the module was built in FIPS mode without ASAN.
+OPENSSL_EXPORT int BORINGSSL_integrity_test(void);
+
// CRYPTO_pre_sandbox_init initializes the crypto library, pre-acquiring some
// unusual resources to aid running in sandboxed environments. It is safe to
// call this function multiple times and concurrently from multiple threads.