Make FFDH self tests lazy.
Change-Id: I7ac046a2422d79b77a231ab65325402658144390
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51566
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/dh/dh.c b/crypto/fipsmodule/dh/dh.c
index ab596e9..b59afc6 100644
--- a/crypto/fipsmodule/dh/dh.c
+++ b/crypto/fipsmodule/dh/dh.c
@@ -64,6 +64,7 @@
#include <openssl/mem.h>
#include <openssl/thread.h>
+#include "internal.h"
#include "../../internal.h"
#include "../bn/internal.h"
@@ -186,6 +187,8 @@
}
int DH_generate_key(DH *dh) {
+ boringssl_ensure_ffdh_self_test();
+
int ok = 0;
int generate_new_key = 0;
BN_CTX *ctx = NULL;
@@ -322,7 +325,8 @@
return ret;
}
-int DH_compute_key_padded(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
+int dh_compute_key_padded_no_self_test(unsigned char *out,
+ const BIGNUM *peers_key, DH *dh) {
BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
return -1;
@@ -343,7 +347,15 @@
return ret;
}
+int DH_compute_key_padded(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
+ boringssl_ensure_ffdh_self_test();
+
+ return dh_compute_key_padded_no_self_test(out, peers_key, dh);
+}
+
int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
+ boringssl_ensure_ffdh_self_test();
+
BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
return -1;
diff --git a/crypto/fipsmodule/dh/internal.h b/crypto/fipsmodule/dh/internal.h
new file mode 100644
index 0000000..c40172d
--- /dev/null
+++ b/crypto/fipsmodule/dh/internal.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2022, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_DH_INTERNAL_H
+#define OPENSSL_HEADER_CRYPTO_FIPSMODULE_DH_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+// dh_compute_key_padded_no_self_test does the same as |DH_compute_key_padded|,
+// but doesn't try to run the self-test first. This is for use in the self tests
+// themselves, to prevent an infinite loop.
+int dh_compute_key_padded_no_self_test(unsigned char *out,
+ const BIGNUM *peers_key, DH *dh);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_DH_INTERNAL_H
diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c
index 7191ca4..b7cd868 100644
--- a/crypto/fipsmodule/self_check/self_check.c
+++ b/crypto/fipsmodule/self_check/self_check.c
@@ -31,6 +31,7 @@
#include <openssl/sha.h>
#include "../../internal.h"
+#include "../dh/internal.h"
#include "../ec/internal.h"
#include "../ecdsa/internal.h"
#include "../rand/internal.h"
@@ -534,40 +535,7 @@
return ret;
}
-#if defined(BORINGSSL_FIPS)
-
-static void run_self_test_rsa(void) {
- if (!boringssl_self_test_rsa()) {
- BORINGSSL_FIPS_abort();
- }
-}
-
-DEFINE_STATIC_ONCE(g_self_test_once_rsa);
-
-void boringssl_ensure_rsa_self_test(void) {
- CRYPTO_once(g_self_test_once_rsa_bss_get(), run_self_test_rsa);
-}
-
-static void run_self_test_ecc(void) {
- if (!boringssl_self_test_ecc()) {
- BORINGSSL_FIPS_abort();
- }
-}
-
-DEFINE_STATIC_ONCE(g_self_test_once_ecc);
-
-void boringssl_ensure_ecc_self_test(void) {
- CRYPTO_once(g_self_test_once_ecc_bss_get(), run_self_test_ecc);
-}
-
-#endif // BORINGSSL_FIPS
-
-
-// Startup self tests.
-//
-// These tests are run at process start when in FIPS mode.
-
-static int boringssl_self_test_slow(void) {
+static int boringssl_self_test_ffdh(void) {
int ret = 0;
DH *dh = NULL;
BIGNUM *ffdhe2048_value = NULL;
@@ -628,7 +596,8 @@
dh = self_test_dh();
uint8_t dh_out[sizeof(kDHOutput)];
if (dh == NULL || ffdhe2048_value == NULL || sizeof(dh_out) != DH_size(dh) ||
- DH_compute_key_padded(dh_out, ffdhe2048_value, dh) != sizeof(dh_out) ||
+ dh_compute_key_padded_no_self_test(dh_out, ffdhe2048_value, dh) !=
+ sizeof(dh_out) ||
!check_test(kDHOutput, dh_out, sizeof(dh_out), "FFC DH")) {
fprintf(stderr, "FFDH failed.\n");
goto err;
@@ -643,6 +612,51 @@
return ret;
}
+#if defined(BORINGSSL_FIPS)
+
+static void run_self_test_rsa(void) {
+ if (!boringssl_self_test_rsa()) {
+ BORINGSSL_FIPS_abort();
+ }
+}
+
+DEFINE_STATIC_ONCE(g_self_test_once_rsa);
+
+void boringssl_ensure_rsa_self_test(void) {
+ CRYPTO_once(g_self_test_once_rsa_bss_get(), run_self_test_rsa);
+}
+
+static void run_self_test_ecc(void) {
+ if (!boringssl_self_test_ecc()) {
+ BORINGSSL_FIPS_abort();
+ }
+}
+
+DEFINE_STATIC_ONCE(g_self_test_once_ecc);
+
+void boringssl_ensure_ecc_self_test(void) {
+ CRYPTO_once(g_self_test_once_ecc_bss_get(), run_self_test_ecc);
+}
+
+static void run_self_test_ffdh(void) {
+ if (!boringssl_self_test_ffdh()) {
+ BORINGSSL_FIPS_abort();
+ }
+}
+
+DEFINE_STATIC_ONCE(g_self_test_once_ffdh);
+
+void boringssl_ensure_ffdh_self_test(void) {
+ CRYPTO_once(g_self_test_once_ffdh_bss_get(), run_self_test_ffdh);
+}
+
+#endif // BORINGSSL_FIPS
+
+
+// Startup self tests.
+//
+// These tests are run at process start when in FIPS mode.
+
int boringssl_self_test_sha256(void) {
static const uint8_t kInput[16] = {
0xff, 0x3b, 0x85, 0x7d, 0xa7, 0x23, 0x6a, 0x2b,
@@ -930,10 +944,10 @@
int BORINGSSL_self_test(void) {
if (!boringssl_self_test_fast() ||
- !boringssl_self_test_slow() ||
// When requested to run self tests, also run the lazy tests.
!boringssl_self_test_rsa() ||
- !boringssl_self_test_ecc()) {
+ !boringssl_self_test_ecc() ||
+ !boringssl_self_test_ffdh()) {
return 0;
}
@@ -942,12 +956,7 @@
#if defined(BORINGSSL_FIPS)
int boringssl_self_test_startup(void) {
- if (!boringssl_self_test_fast() ||
- !boringssl_self_test_slow()) {
- return 0;
- }
-
- return 1;
+ return boringssl_self_test_fast();
}
#endif
diff --git a/crypto/internal.h b/crypto/internal.h
index d8647eb..78dbbbf 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -957,12 +957,18 @@
// address space if unsuccessful.
void boringssl_ensure_ecc_self_test(void);
+// boringssl_ensure_ffdh_self_test checks whether the FFDH self-test has been
+// run in this address space. If not, it runs it and crashes the address space
+// if unsuccessful.
+void boringssl_ensure_ffdh_self_test(void);
+
#else
// Outside of FIPS mode, the lazy tests are no-ops.
OPENSSL_INLINE void boringssl_ensure_rsa_self_test(void) {}
OPENSSL_INLINE void boringssl_ensure_ecc_self_test(void) {}
+OPENSSL_INLINE void boringssl_ensure_ffdh_self_test(void) {}
#endif // FIPS