From f2e7b220c01164385914d63d47c6fbd42c740a3c Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 22 Jan 2018 11:07:42 -0800 Subject: [PATCH] Extract FIPS KAT tests into a function. This change adds |BORINGSSL_self_test|, which allows applications to run the FIPS KAT tests on demand, even in non-FIPS builds. Change-Id: I950b30a02ab030d5e05f2d86148beb4ee1b5929c Reviewed-on: https://boringssl-review.googlesource.com/25044 Commit-Queue: Adam Langley CQ-Verified: CQ bot account: commit-bot@chromium.org Reviewed-by: David Benjamin --- crypto/CMakeLists.txt | 1 + crypto/fipsmodule/bcm.c | 117 +++++++++++++++++++++++---------------- crypto/self_test.cc | 24 ++++++++ include/openssl/crypto.h | 4 ++ 4 files changed, 98 insertions(+), 48 deletions(-) create mode 100644 crypto/self_test.cc diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index a090b3e1..3ca223b4 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -260,6 +260,7 @@ add_executable( pool/pool_test.cc refcount_test.cc rsa_extra/rsa_test.cc + self_test.cc test/file_test_gtest.cc thread_test.cc x509/x509_test.cc diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 2e2723f8..3e1890fc 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -95,7 +95,9 @@ #include "tls/kdf.c" -#if defined(BORINGSSL_FIPS) +// MSVC wants to put a NUL byte at the end of non-char arrays and so cannot +// compile this. +#if !defined(_MSC_VER) static void hexdump(const uint8_t *in, size_t len) { for (size_t i = 0; i < len; i++) { @@ -288,41 +290,7 @@ static EC_KEY *self_test_ecdsa_key(void) { return ec_key; } -#if !defined(OPENSSL_ASAN) -// These symbols are filled in by delocate.go. They point to the start and end -// of the module, and the location of the integrity hash, respectively. -extern const uint8_t BORINGSSL_bcm_text_start[]; -extern const uint8_t BORINGSSL_bcm_text_end[]; -extern const uint8_t BORINGSSL_bcm_text_hash[]; -#endif - -static void __attribute__((constructor)) -BORINGSSL_bcm_power_on_self_test(void) { - CRYPTO_library_init(); - -#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. - const uint8_t *const start = BORINGSSL_bcm_text_start; - const uint8_t *const end = BORINGSSL_bcm_text_end; - - static const uint8_t kHMACKey[64] = {0}; - uint8_t result[SHA512_DIGEST_LENGTH]; - - unsigned result_len; - if (!HMAC(EVP_sha512(), kHMACKey, sizeof(kHMACKey), start, end - start, - result, &result_len) || - result_len != sizeof(result)) { - goto err; - } - - const uint8_t *expected = BORINGSSL_bcm_text_hash; - - if (!check_test(expected, result, sizeof(result), "FIPS integrity test")) { - goto err; - } -#endif - +int BORINGSSL_self_test(void) { static const uint8_t kAESKey[16] = "BoringCrypto Key"; static const uint8_t kAESIV[16] = {0}; static const uint8_t kPlaintext[64] = @@ -475,6 +443,13 @@ BORINGSSL_bcm_power_on_self_test(void) { 0xf0, 0xcc, 0x81, 0xe5, 0xea, 0x3f, 0xc2, 0x41, 0x7f, 0xd8, }; + EVP_AEAD_CTX aead_ctx; + EVP_AEAD_CTX_zero(&aead_ctx); + RSA *rsa_key = NULL; + EC_KEY *ec_key = NULL; + ECDSA_SIG *sig = NULL; + int ret = 0; + AES_KEY aes_key; uint8_t aes_iv[16]; uint8_t output[256]; @@ -506,7 +481,6 @@ BORINGSSL_bcm_power_on_self_test(void) { size_t out_len; uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; OPENSSL_memset(nonce, 0, sizeof(nonce)); - EVP_AEAD_CTX aead_ctx; if (!EVP_AEAD_CTX_init(&aead_ctx, EVP_aead_aes_128_gcm(), kAESKey, sizeof(kAESKey), 0, NULL)) { goto err; @@ -531,8 +505,6 @@ BORINGSSL_bcm_power_on_self_test(void) { goto err; } - EVP_AEAD_CTX_cleanup(&aead_ctx); - DES_key_schedule des1, des2, des3; DES_cblock des_iv; DES_set_key(&kDESKey1, &des1); @@ -578,7 +550,7 @@ BORINGSSL_bcm_power_on_self_test(void) { goto err; } - RSA *rsa_key = self_test_rsa_key(); + rsa_key = self_test_rsa_key(); if (rsa_key == NULL) { printf("RSA KeyGen failed\n"); goto err; @@ -605,9 +577,7 @@ BORINGSSL_bcm_power_on_self_test(void) { goto err; } - RSA_free(rsa_key); - - EC_KEY *ec_key = self_test_ecdsa_key(); + ec_key = self_test_ecdsa_key(); if (ec_key == NULL) { printf("ECDSA KeyGen failed\n"); goto err; @@ -623,8 +593,7 @@ BORINGSSL_bcm_power_on_self_test(void) { goto err; } - ECDSA_SIG *sig = - ECDSA_do_sign(kPlaintextSHA256, sizeof(kPlaintextSHA256), ec_key); + sig = ECDSA_do_sign(kPlaintextSHA256, sizeof(kPlaintextSHA256), ec_key); uint8_t ecdsa_r_bytes[sizeof(kECDSASigR)]; uint8_t ecdsa_s_bytes[sizeof(kECDSASigS)]; @@ -639,9 +608,6 @@ BORINGSSL_bcm_power_on_self_test(void) { goto err; } - ECDSA_SIG_free(sig); - EC_KEY_free(ec_key); - // DBRG KAT CTR_DRBG_STATE drbg; if (!CTR_DRBG_init(&drbg, kDRBGEntropy, kDRBGPersonalization, @@ -665,6 +631,58 @@ BORINGSSL_bcm_power_on_self_test(void) { goto err; } + ret = 1; + +err: + EVP_AEAD_CTX_cleanup(&aead_ctx); + RSA_free(rsa_key); + EC_KEY_free(ec_key); + ECDSA_SIG_free(sig); + + return ret; +} + +#if defined(BORINGSSL_FIPS) + +#if !defined(OPENSSL_ASAN) +// These symbols are filled in by delocate.go. They point to the start and end +// of the module, and the location of the integrity hash, respectively. +extern const uint8_t BORINGSSL_bcm_text_start[]; +extern const uint8_t BORINGSSL_bcm_text_end[]; +extern const uint8_t BORINGSSL_bcm_text_hash[]; +#endif + +static void __attribute__((constructor)) +BORINGSSL_bcm_power_on_self_test(void) { + CRYPTO_library_init(); + +#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. + const uint8_t *const start = BORINGSSL_bcm_text_start; + const uint8_t *const end = BORINGSSL_bcm_text_end; + + static const uint8_t kHMACKey[64] = {0}; + uint8_t result[SHA512_DIGEST_LENGTH]; + + unsigned result_len; + if (!HMAC(EVP_sha512(), kHMACKey, sizeof(kHMACKey), start, end - start, + result, &result_len) || + result_len != sizeof(result)) { + goto err; + } + + const uint8_t *expected = BORINGSSL_bcm_text_hash; + + if (!check_test(expected, result, sizeof(result), "FIPS integrity test")) { + goto err; + } +#endif + + if (!BORINGSSL_self_test()) { + goto err; + } + return; err: @@ -677,4 +695,7 @@ void BORINGSSL_FIPS_abort(void) { exit(1); } } + #endif // BORINGSSL_FIPS + +#endif // !_MSC_VER diff --git a/crypto/self_test.cc b/crypto/self_test.cc new file mode 100644 index 00000000..c20b5def --- /dev/null +++ b/crypto/self_test.cc @@ -0,0 +1,24 @@ +/* Copyright (c) 2018, 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 + +#include + + +TEST(SelfTests, KAT) { +#if !defined(_MSC_VER) + EXPECT_TRUE(BORINGSSL_self_test()); +#endif +} diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h index dc87dd2d..ccf5012c 100644 --- a/include/openssl/crypto.h +++ b/include/openssl/crypto.h @@ -58,6 +58,10 @@ OPENSSL_EXPORT int CRYPTO_has_asm(void); // 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); + // Deprecated functions.