Skip to content

Commit

Permalink
Add support to define a callback for FIPS test failures instead of ab…
Browse files Browse the repository at this point in the history
…orting the process (#2162)

### Description of changes: 
This change adds a new build option `AWSLC_FIPS_FAILURE_CALLBACK` that
then requires applications that links with AWS-LC to define the
`AWS_LC_fips_failure_callback(const char* message)` function. If that
function is not defined AWS-LC fails to load.

When the callback is defined and a FIPS failure (CAST or PWCT) happens
AWS-LC calls that function instead. It is up to the calling application
to ensure no further cryptographic operations occur. This is not an
approved way to use AWS-LC in FIPS mode, for the approved way to build
and use AWS-LC see the latest FIPS security policy.

### Testing
This change adds a new gtest that checks the callback
function is called with the expected message and is used with
break-kat.go and the runtime PCT environment variables to ensure the
callback is passed the expected message.


By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
  • Loading branch information
andrewhop authored Feb 25, 2025
1 parent db713ea commit dc3b44b
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 30 deletions.
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,7 @@ if(BUILD_TESTING)
evp_extra/evp_test.cc
evp_extra/p_pqdsa_test.cc
evp_extra/scrypt_test.cc
fips_callback_test.cc
fipsmodule/aes/aes_test.cc
fipsmodule/bn/bn_test.cc
fipsmodule/bn/bn_assert_test.cc
Expand Down
168 changes: 168 additions & 0 deletions crypto/fips_callback_test.cc

Large diffs are not rendered by default.

26 changes: 25 additions & 1 deletion crypto/fipsmodule/bcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@ static void BORINGSSL_maybe_set_module_text_permissions(int _permission) {}

#endif // !ASAN

#if defined(AWSLC_FIPS_FAILURE_CALLBACK)
#if defined(__ELF__) && defined(__GNUC__)
WEAK_SYMBOL_FUNC(void, AWS_LC_fips_failure_callback, (const char* message))
#else
#error AWSLC_FIPS_FAILURE_CALLBACK not supported on this platform
#endif
#endif

#if defined(_MSC_VER)
#pragma section(".CRT$XCU", read)
static void BORINGSSL_bcm_power_on_self_test(void);
Expand All @@ -262,6 +270,13 @@ static void BORINGSSL_bcm_power_on_self_test(void) __attribute__ ((constructor))
#endif

static void BORINGSSL_bcm_power_on_self_test(void) {
#if defined(AWSLC_FIPS_FAILURE_CALLBACK)
if (AWS_LC_fips_failure_callback == NULL) {
fprintf(stderr, "AWS_LC_fips_failure_callback not defined but AWS-LC built with AWSLC_FIPS_FAILURE_CALLBACK\n");
fflush(stderr);
abort();
}
#endif
// TODO: remove !defined(OPENSSL_PPC64BE) from the check below when starting to support
// PPC64BE that has VCRYPTO capability. In that case, add `|| defined(OPENSSL_PPC64BE)`
// to `#if defined(OPENSSL_PPC64LE)` wherever it occurs.
Expand Down Expand Up @@ -392,14 +407,23 @@ int BORINGSSL_integrity_test(void) {
#endif // OPENSSL_ASAN

void AWS_LC_FIPS_failure(const char* message) {
#if defined(AWSLC_FIPS_FAILURE_CALLBACK)
if (AWS_LC_fips_failure_callback == NULL) {
fprintf(stderr, "AWS_LC_fips_failure_callback not defined but AWS-LC built with AWSLC_FIPS_FAILURE_CALLBACK. FIPS failure:\n%s", message);
fflush(stderr);
abort();
} else {
AWS_LC_fips_failure_callback(message);
}
#else
fprintf(stderr, "AWS-LC FIPS failure caused by:\n%s\n", message);
fflush(stderr);
for (;;) {
abort();
exit(1);
}
#endif
}

#else // BORINGSSL_FIPS
void AWS_LC_FIPS_failure(const char* message) {
fprintf(stderr, "AWS-LC FIPS failure caused by:\n%s\n", message);
Expand Down
31 changes: 15 additions & 16 deletions crypto/fipsmodule/self_check/self_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ static int boringssl_self_test_ecc(void) {
ec_point_in = EC_POINT_new(ec_group);
ec_point_out = EC_POINT_new(ec_group);
ec_scalar = BN_new();
uint8_t z_comp_result[65];
uint8_t z_comp_result[65] = {0};
if (ec_point_in == NULL || ec_point_out == NULL || ec_scalar == NULL ||
!EC_POINT_oct2point(ec_group, ec_point_in, kP256Point, sizeof(kP256Point),
NULL) ||
Expand Down Expand Up @@ -2276,7 +2276,7 @@ void boringssl_ensure_ffdh_self_test(void) {

static void run_self_test_ml_kem(void) {
if (!boringssl_self_test_ml_kem()) {
AWS_LC_FIPS_failure("RSA self tests failed");
AWS_LC_FIPS_failure("ML-KEM self tests failed");
}
}

Expand Down Expand Up @@ -2390,9 +2390,10 @@ int boringssl_self_test_hmac_sha256(void) {
}

static int boringssl_self_test_hkdf_sha256(void) {
static const uint8_t kHKDF_ikm_tc1[] = { // RFC 5869 Test Case 1
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
static const uint8_t kHKDF_ikm_tc1[] = {
0x58, 0x3e, 0xa3, 0xcf, 0x8f, 0xcf, 0xc8, 0x08, 0x73, 0xcc, 0x7b, 0x88,
0x00, 0x9d, 0x4a, 0xed, 0x07, 0xd8, 0xd8, 0x88, 0xae, 0x98, 0x76, 0x8d,
0xca, 0x07, 0xcb, 0x1e, 0x4b, 0x33, 0x1e, 0xb9
};
static const uint8_t kHKDF_salt_tc1[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
Expand All @@ -2402,10 +2403,10 @@ static int boringssl_self_test_hkdf_sha256(void) {
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9
};
static const uint8_t kHKDF_okm_tc1_sha256[] = {
0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64,
0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08,
0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65
0xca, 0x5e, 0x64, 0x10, 0xe7, 0xa5, 0x23, 0x32, 0xfe, 0x0a, 0xb3, 0x60,
0x12, 0x12, 0xa7, 0xd3, 0xdb, 0xdf, 0x55, 0xa1, 0x62, 0xaf, 0x42, 0xa5,
0xda, 0xf3, 0x8b, 0x94, 0xf2, 0x45, 0x23, 0x47, 0x7e, 0x88, 0x0d, 0xd7,
0x11, 0x50, 0x86, 0x84, 0xcc, 0x21
};

uint8_t output[sizeof(kHKDF_okm_tc1_sha256)];
Expand Down Expand Up @@ -2669,11 +2670,9 @@ static int boringssl_self_test_fast(void) {
goto err;
}

// PBKDF2 KAT - password/salt data from RFC 6070, derived key generated by
// Python's cryptography module
static const uint8_t kPBKDF2Password[] = {
'p', 'a', 's', 's', 'w', 'o', 'r', 'd', 'P', 'A', 'S', 'S', 'W', 'O', 'R',
'D', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'
'A', 'W', 'S', '-', 'L', 'C', 'F', 'I', 'P', 'S', 'p', 'a', 's', 's', 'w',
'o', 'r', 'd'
};
static const uint8_t kPBKDF2Salt[] = {
's', 'a', 'l', 't', 'S', 'A', 'L', 'T', 's', 'a', 'l', 't', 'S', 'A', 'L',
Expand All @@ -2682,9 +2681,9 @@ static int boringssl_self_test_fast(void) {
};
const unsigned kPBKDF2Iterations = 2;
static const uint8_t kPBKDF2DerivedKey[] = {
0x13, 0xdc, 0x8a, 0x7c, 0x13, 0xd3, 0x72, 0xc9, 0x03, 0x82, 0x82, 0x2d,
0x2d, 0xc4, 0x92, 0xf2, 0xed, 0x52, 0x46, 0x7f, 0xb7, 0x82, 0x8e, 0xa8,
0x64 // 25 bytes
0xc6, 0xac, 0x07, 0x79, 0xe4, 0xa1, 0x17, 0xc9, 0x22, 0x28, 0x7f, 0x5e,
0x10, 0xe7, 0xee, 0x6b, 0xa7, 0x4d, 0x8b, 0x19, 0x51, 0x9b, 0x4c, 0xc7,
0x38
};
uint8_t pbkdf2_output[sizeof(kPBKDF2DerivedKey)];
if (!PKCS5_PBKDF2_HMAC((const char *)kPBKDF2Password, sizeof(kPBKDF2Password),
Expand Down
16 changes: 15 additions & 1 deletion crypto/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1272,12 +1272,15 @@ static inline uint64_t CRYPTO_subc_u64(uint64_t x, uint64_t y, uint64_t borrow,
// AWS_LC_FIPS_failure is called when a FIPS power-on or continuous test
// fails. If the library is built in FIPS mode it prevents any further
// cryptographic operations by the current process.
#if defined(AWSLC_FIPS_FAILURE_CALLBACK)
void AWS_LC_FIPS_failure(const char* message);
#else
#if defined(_MSC_VER)
__declspec(noreturn) void AWS_LC_FIPS_failure(const char* message);
#else
void AWS_LC_FIPS_failure(const char* message) __attribute__((noreturn));
#endif

#endif
// boringssl_self_test_startup runs all startup self tests and returns one on
// success or zero on error. Startup self tests do not include lazy tests.
// Call |BORINGSSL_self_test| to run every self test.
Expand Down Expand Up @@ -1420,6 +1423,17 @@ OPENSSL_EXPORT int OPENSSL_vasprintf_internal(char **str, const char *format,
#define GUARD_PTR(ptr) __AWS_LC_ENSURE((ptr) != NULL, OPENSSL_PUT_ERROR(CRYPTO, ERR_R_PASSED_NULL_PARAMETER); \
return AWS_LC_ERROR)


// Windows doesn't really support weak symbols as of May 2019, and Clang on
// Windows will emit strong symbols instead. See
// https://bugs.llvm.org/show_bug.cgi?id=37598
#if defined(__ELF__) && defined(__GNUC__)
#define WEAK_SYMBOL_FUNC(rettype, name, args) \
rettype name args __attribute__((weak));
#else
#define WEAK_SYMBOL_FUNC(rettype, name, args) static rettype(*name) args = NULL;
#endif

#if defined(__cplusplus)
} // extern C
#endif
Expand Down
10 changes: 0 additions & 10 deletions crypto/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,6 @@ static void __asan_poison_memory_region(const void *addr, size_t size) {}
static void __asan_unpoison_memory_region(const void *addr, size_t size) {}
#endif

// Windows doesn't really support weak symbols as of May 2019, and Clang on
// Windows will emit strong symbols instead. See
// https://bugs.llvm.org/show_bug.cgi?id=37598
#if defined(__ELF__) && defined(__GNUC__)
#define WEAK_SYMBOL_FUNC(rettype, name, args) \
rettype name args __attribute__((weak));
#else
#define WEAK_SYMBOL_FUNC(rettype, name, args) static rettype(*name) args = NULL;
#endif

#define AWSLC_FILE ""
#define AWSLC_LINE 0

Expand Down
29 changes: 29 additions & 0 deletions tests/ci/run_fips_callback_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -ex
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR ISC
source tests/ci/common_posix_setup.sh

original_test="${BUILD_ROOT}/crypto/crypto_test"
broken_test="${BUILD_ROOT}/crypto/crypto_test_broken"

# By default the test should pass
$original_test --gtest_filter=FIPSCallback.PowerOnSelfTests
$original_test --gtest_filter=FIPSCallback.PWCT

# Break the tests
KATS=$(go run "${SRC_ROOT}/util/fipstools/break-kat.go" --list-tests)
for kat in $KATS; do
go run "${SRC_ROOT}/util/fipstools/break-kat.go" "$original_test" "$kat" > "$broken_test"
chmod +x "$broken_test"
export FIPS_CALLBACK_TEST_EXPECTED_FAILURE="$kat"
# When a callback is defined AWS-LC will not abort and the test should exit successfully
$broken_test --gtest_filter=FIPSCallback.PowerOnSelfTests
unset FIPS_CALLBACK_TEST_EXPECTED_FAILURE
done

for TEST in RSA_PWCT ECDSA_PWCT EDDSA_PWCT MLKEM_PWCT MLDSA_PWCT; do
export FIPS_CALLBACK_TEST_EXPECTED_FAILURE="${TEST}"
export BORINGSSL_FIPS_BREAK_TEST="${TEST}"
$original_test --gtest_filter=FIPSCallback.PWCT
done
4 changes: 4 additions & 0 deletions tests/ci/run_fips_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ if static_linux_supported || static_openbsd_supported; then
echo "Testing AWS-LC static library in FIPS Release mode."
fips_build_and_test -DCMAKE_BUILD_TYPE=Release

echo "Testing AWS-LC static breakable build with custom callback enabled"
run_build -DFIPS=1 -DCMAKE_C_FLAGS="-DBORINGSSL_FIPS_BREAK_TESTS -DAWSLC_FIPS_FAILURE_CALLBACK"
./tests/ci/run_fips_callback_tests.sh

echo "Testing AWS-LC static breakable release build"
run_build -DFIPS=1 -DCMAKE_C_FLAGS="-DBORINGSSL_FIPS_BREAK_TESTS"
./util/fipstools/test-break-kat.sh
Expand Down
4 changes: 2 additions & 2 deletions util/fipstools/break-kat.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ var (
"SHA-256": "ff3b857da7236a2baa0f396b51522217",
"SHA-512": "212512f8d2ad8322781c6c4d69a9daa1",
"SHA3-256": "d83c721ee51b060c5a41438a8221e040",
"HKDF-SHA-256": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"HKDF-SHA-256": "ca5e6410e7a52332fe0ab3601212a7d3dbdf55a162af42a5daf38b94f24523477e880dd711508684cc21",
"TLS-KDF": "abc3657b094c7628a0b282996fe75a75f4984fd94d4ecc2fcf53a2c469a3f731",
"PBKDF2": "70617373776F726450415353574F524470617373776F7264",
"PBKDF2": "4157532d4c434649505370617373776f7264",
"SSKDF": "39a1e2b3899e87efecf6271282d8f8008f252686dd35bfc39a0f71478da48c691565cee431254dd50cab7462c6cf199be9bf5c",
"KBKDF": "dd1d91b7d90b2bd3138533ce92b272fbf8a369316aefe242e659cc0ae238afe0",
"RSA-sign": "d2b56e53306f720d7929d8708bf46f1c22300305582b115bedcac722d8aa5ab2",
Expand Down

0 comments on commit dc3b44b

Please sign in to comment.