fips: add counters.
In order to provide evidence to auditors that high-level functions end
up calling into the FIPS module, provide counters that allow for such
monitoring.
Change-Id: I55d45299f3050bf58077715ffa280210db156116
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/46124
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/crypto_test.cc b/crypto/crypto_test.cc
index f6c2374..ccb0956 100644
--- a/crypto/crypto_test.cc
+++ b/crypto/crypto_test.cc
@@ -19,6 +19,7 @@
#include <openssl/base.h>
#include <openssl/crypto.h>
+#include <openssl/cipher.h>
#include <gtest/gtest.h>
@@ -33,3 +34,33 @@
EXPECT_EQ(expected,
std::string(OPENSSL_VERSION_TEXT).substr(0, strlen(expected)));
}
+
+#if defined(BORINGSSL_FIPS_COUNTERS)
+TEST(CryptoTest, FIPSCountersEVP) {
+ constexpr struct {
+ const EVP_CIPHER *(*cipher)();
+ fips_counter_t counter;
+ } kTests[] = {
+ {
+ EVP_aes_128_gcm,
+ fips_counter_evp_aes_128_gcm,
+ },
+ {
+ EVP_aes_256_gcm,
+ fips_counter_evp_aes_256_gcm,
+ },
+ };
+
+ uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
+ uint8_t iv[EVP_MAX_IV_LENGTH] = {1};
+
+ for (const auto& test : kTests) {
+ const size_t before = FIPS_read_counter(test.counter);
+
+ bssl::ScopedEVP_CIPHER_CTX ctx;
+ ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), test.cipher(), /*engine=*/nullptr,
+ key, iv));
+ ASSERT_GT(FIPS_read_counter(test.counter), before);
+ }
+}
+#endif // BORINGSSL_FIPS_COUNTERS
diff --git a/crypto/fipsmodule/CMakeLists.txt b/crypto/fipsmodule/CMakeLists.txt
index 83cf3f7..d22100f 100644
--- a/crypto/fipsmodule/CMakeLists.txt
+++ b/crypto/fipsmodule/CMakeLists.txt
@@ -223,7 +223,6 @@
OBJECT
fips_shared_support.c
- is_fips.c
)
add_dependencies(fipsmodule global_target)
@@ -240,7 +239,6 @@
OBJECT
fips_shared_support.c
- is_fips.c
)
add_dependencies(fipsmodule global_target)
@@ -273,7 +271,6 @@
bcm.c
fips_shared_support.c
- is_fips.c
${BCM_ASM_SOURCES}
)
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index 601c4a8..61479ed 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -79,6 +79,7 @@
#include "ec/simple_mul.c"
#include "ec/util.c"
#include "ec/wnaf.c"
+#include "fips.c"
#include "hmac/hmac.c"
#include "md4/md4.c"
#include "md5/md5.c"
diff --git a/crypto/fipsmodule/cipher/e_aes.c b/crypto/fipsmodule/cipher/e_aes.c
index 6df2b7b..9186186 100644
--- a/crypto/fipsmodule/cipher/e_aes.c
+++ b/crypto/fipsmodule/cipher/e_aes.c
@@ -353,6 +353,17 @@
if (!iv && !key) {
return 1;
}
+
+ switch (ctx->key_len) {
+ case 16:
+ boringssl_fips_inc_counter(fips_counter_evp_aes_128_gcm);
+ break;
+
+ case 32:
+ boringssl_fips_inc_counter(fips_counter_evp_aes_256_gcm);
+ break;
+ }
+
if (key) {
OPENSSL_memset(&gctx->gcm, 0, sizeof(gctx->gcm));
gctx->ctr = aes_ctr_set_key(&gctx->ks.ks, &gctx->gcm.gcm_key, NULL, key,
diff --git a/crypto/fipsmodule/fips.c b/crypto/fipsmodule/fips.c
new file mode 100644
index 0000000..07554e4
--- /dev/null
+++ b/crypto/fipsmodule/fips.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2017, 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. */
+
+#include <openssl/crypto.h>
+
+#include "../internal.h"
+#include "delocate.h"
+
+
+int FIPS_mode(void) {
+#if defined(BORINGSSL_FIPS) && !defined(OPENSSL_ASAN)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+int FIPS_mode_set(int on) { return on == FIPS_mode(); }
+
+#if defined(BORINGSSL_FIPS_COUNTERS)
+
+size_t FIPS_read_counter(enum fips_counter_t counter) {
+ if (counter < 0 || counter > fips_counter_max) {
+ abort();
+ }
+
+ const size_t *array =
+ CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS);
+ if (!array) {
+ return 0;
+ }
+
+ return array[counter];
+}
+
+void boringssl_fips_inc_counter(enum fips_counter_t counter) {
+ if (counter < 0 || counter > fips_counter_max) {
+ abort();
+ }
+
+ size_t *array =
+ CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS);
+ if (!array) {
+ array = OPENSSL_malloc(sizeof(size_t) * (fips_counter_max + 1));
+ if (!array) {
+ return;
+ }
+ if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS, array,
+ OPENSSL_free)) {
+ // |OPENSSL_free| has already been called by |CRYPTO_set_thread_local|.
+ return;
+ }
+ }
+
+ array[counter]++;
+}
+
+#else
+
+size_t FIPS_read_counter(enum fips_counter_t counter) { return 0; }
+
+// boringssl_fips_inc_counter is a no-op, inline function in internal.h in this
+// case. That should let the compiler optimise away the callsites.
+
+#endif
diff --git a/crypto/fipsmodule/is_fips.c b/crypto/fipsmodule/is_fips.c
deleted file mode 100644
index 2f8e408..0000000
--- a/crypto/fipsmodule/is_fips.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Copyright (c) 2017, 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. */
-
-#include <openssl/crypto.h>
-
-
-// This file exists in order to give the fipsmodule target, in non-FIPS mode,
-// something to compile.
-
-int FIPS_mode(void) {
-#if defined(BORINGSSL_FIPS) && !defined(OPENSSL_ASAN)
- return 1;
-#else
- return 0;
-#endif
-}
-
-int FIPS_mode_set(int on) { return on == FIPS_mode(); }
diff --git a/crypto/internal.h b/crypto/internal.h
index edba9f9..c574645 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -109,6 +109,7 @@
#ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H
#define OPENSSL_HEADER_CRYPTO_INTERNAL_H
+#include <openssl/crypto.h>
#include <openssl/ex_data.h>
#include <openssl/stack.h>
#include <openssl/thread.h>
@@ -607,6 +608,7 @@
typedef enum {
OPENSSL_THREAD_LOCAL_ERR = 0,
OPENSSL_THREAD_LOCAL_RAND,
+ OPENSSL_THREAD_LOCAL_FIPS_COUNTERS,
OPENSSL_THREAD_LOCAL_TEST,
NUM_OPENSSL_THREAD_LOCALS,
} thread_local_data_t;
@@ -826,6 +828,11 @@
int boringssl_fips_self_test(const uint8_t *module_hash,
size_t module_hash_len);
+#if defined(BORINGSSL_FIPS_COUNTERS)
+void boringssl_fips_inc_counter(enum fips_counter_t counter);
+#else
+OPENSSL_INLINE void boringssl_fips_inc_counter(enum fips_counter_t counter) {}
+#endif
#if defined(__cplusplus)
} // extern C
diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h
index b820e40..e3773e5 100644
--- a/include/openssl/crypto.h
+++ b/include/openssl/crypto.h
@@ -55,10 +55,6 @@
// in which case it returns zero.
OPENSSL_EXPORT int CRYPTO_has_asm(void);
-// FIPS_mode returns zero unless BoringSSL is built with BORINGSSL_FIPS, in
-// which case it returns one.
-OPENSSL_EXPORT int FIPS_mode(void);
-
// BORINGSSL_self_test triggers the FIPS KAT-based self tests. It returns one on
// success and zero on error.
OPENSSL_EXPORT int BORINGSSL_self_test(void);
@@ -72,6 +68,28 @@
OPENSSL_EXPORT void CRYPTO_pre_sandbox_init(void);
+// FIPS monitoring
+
+// FIPS_mode returns zero unless BoringSSL is built with BORINGSSL_FIPS, in
+// which case it returns one.
+OPENSSL_EXPORT int FIPS_mode(void);
+
+// fips_counter_t denotes specific APIs/algorithms. A counter is maintained for
+// each in FIPS mode so that tests can be written to assert that the expected,
+// FIPS functions are being called by a certain peice of code.
+enum fips_counter_t {
+ fips_counter_evp_aes_128_gcm = 0,
+ fips_counter_evp_aes_256_gcm = 1,
+
+ fips_counter_max = 1,
+};
+
+// FIPS_read_counter returns a counter of the number of times the specific
+// function denoted by |counter| has been used. This always returns zero unless
+// BoringSSL was built with BORINGSSL_FIPS_COUNTERS defined.
+OPENSSL_EXPORT size_t FIPS_read_counter(enum fips_counter_t counter);
+
+
// Deprecated functions.
// OPENSSL_VERSION_TEXT contains a string the identifies the version of