diff --git a/BUILDING.md b/BUILDING.md index bcd3790624..1327dd09a9 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -229,3 +229,15 @@ range of unit tests, as well as running valgrind and SDE tests. Building without produces a new target, `run_minimal_tests` in place of `run_tests`. More information on this can be found in [INCORPORATING.md](/INCORPORATING.md). + +# Snapsafe Detection + +AWS-LC supports Snapsafe-type uniqueness breaking event detection +on Linux using SysGenID (https://lkml.org/lkml/2021/3/8/677). This mechanism +is used for security hardening. If a SysGenID interface is not found, then the +mechanism is ignored. + +## Snapsafe Prerequisites + +Snapshots taken on active hosts can potentially be unsafe to use. +See "Snapshot Safety Prerequisites" here: https://lkml.org/lkml/2021/3/8/677 diff --git a/CMakeLists.txt b/CMakeLists.txt index f79264b6c6..57fba87fd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,13 @@ install(DIRECTORY include/openssl PATTERN boringssl_prefix_symbols_nasm.inc EXCLUDE ) +if (TEST_SYSGENID_PATH) + message(STATUS "Setting AWSLC_SNAPSAFE_TESTING=1") + add_definitions(-DAWSLC_SNAPSAFE_TESTING=1) + message(STATUS "Setting AWSLC_SYSGENID_PATH=${TEST_SYSGENID_PATH}") + add_definitions(-DAWSLC_SYSGENID_PATH=\"${TEST_SYSGENID_PATH}\") +endif() + if(ANDROID) # Android-NDK CMake files reconfigure the path and so Perl won't be found. # However, ninja will still find them in $PATH if we just name them. diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index dcf21e49a2..817eef3013 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -719,6 +719,7 @@ if(BUILD_TESTING) fipsmodule/rand/ctrdrbg_test.cc fipsmodule/rand/cpu_jitter_test.cc fipsmodule/rand/fork_detect_test.cc + fipsmodule/rand/snapsafe_detect_test.cc fipsmodule/service_indicator/service_indicator_test.cc fipsmodule/sha/sha_test.cc fipsmodule/sha/sha3_test.cc diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 79d9d30a16..4239d7a20c 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -125,6 +125,7 @@ #include "rand/ctrdrbg.c" #include "rand/fork_detect.c" #include "rand/rand.c" +#include "rand/snapsafe_detect.c" #include "rand/urandom.c" #include "rsa/blinding.c" #include "rsa/padding.c" diff --git a/crypto/fipsmodule/rand/rand.c b/crypto/fipsmodule/rand/rand.c index a89d7c6d0c..b229e2a0b8 100644 --- a/crypto/fipsmodule/rand/rand.c +++ b/crypto/fipsmodule/rand/rand.c @@ -35,6 +35,7 @@ #include "internal.h" #include "fork_detect.h" +#include "snapsafe_detect.h" #include "../../internal.h" #include "../delocate.h" @@ -54,14 +55,14 @@ // This might be a bit of a leap of faith, esp on Windows, but there's nothing // that we can do about it.) -// When in FIPS mode we use the CPU Jitter entropy source to seed our DRBG. +// When in FIPS mode we use the CPU Jitter entropy source to seed our DRBG. // This entropy source is very slow and can incur a cost anywhere between 10-60ms -// depending on configuration and CPU. Increasing to 2^24 will amortize the -// penalty over more requests. This is the same value used in OpenSSL 3.0 +// depending on configuration and CPU. Increasing to 2^24 will amortize the +// penalty over more requests. This is the same value used in OpenSSL 3.0 // and meets the requirements defined in SP 800-90B for a max reseed of interval (2^48) // // CPU Jitter: https://www.chronox.de/jent/doc/CPU-Jitter-NPTRNG.html -// +// // kReseedInterval is the number of generate calls made to CTR-DRBG before // reseeding. @@ -96,6 +97,13 @@ struct rand_thread_state { // calls is the number of generate calls made on |drbg| since it was last // (re)seeded. This is bound by |kReseedInterval|. unsigned calls; + // fork_unsafe_buffering is non-zero iff, when |drbg| was last (re)seeded, + // fork-unsafe buffering was enabled. + int fork_unsafe_buffering; + + // snapsafe_generation is non-zero when active. When the value changes, + // the drbg state must be reseeded. + uint32_t snapsafe_generation; #if defined(BORINGSSL_FIPS) // next and prev form a NULL-terminated, double-linked list of all states in @@ -317,6 +325,12 @@ static int rdrand(uint8_t *buf, size_t len) { #if defined(BORINGSSL_FIPS) #if defined(FIPS_ENTROPY_SOURCE_PASSIVE) + +// Currently, we assume that the length of externally loaded entropy has the +// same length as the seed used in the ctr-drbg. +OPENSSL_STATIC_ASSERT(CTR_DRBG_ENTROPY_LEN == PASSIVE_ENTROPY_LOAD_LENGTH, + passive_entropy_load_length_different_from_ctr_drbg_seed_length) + void RAND_load_entropy(uint8_t out_entropy[CTR_DRBG_ENTROPY_LEN], uint8_t entropy[PASSIVE_ENTROPY_LOAD_LENGTH]) { OPENSSL_memcpy(out_entropy, entropy, CTR_DRBG_ENTROPY_LEN); @@ -355,8 +369,9 @@ static void rand_get_seed(struct rand_thread_state *state, static void rand_get_seed(struct rand_thread_state *state, uint8_t seed[CTR_DRBG_ENTROPY_LEN], int *out_want_additional_input) { - // If not in FIPS mode, we don't overread from the system entropy source and - // we don't depend only on the hardware RDRAND. + // If not in FIPS mode, we use the system entropy source. + // We don't source the entropy directly from the CPU. + // Therefore, |*out_want_additonal_input| is set to zero. CRYPTO_sysrand_for_seed(seed, CTR_DRBG_ENTROPY_LEN); *out_want_additional_input = 0; } @@ -370,6 +385,10 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len, } const uint64_t fork_generation = CRYPTO_get_fork_generation(); + const int fork_unsafe_buffering = rand_fork_unsafe_buffering_enabled(); + + uint32_t snapsafe_generation = 0; + int snapsafe_status = CRYPTO_get_snapsafe_generation(&snapsafe_generation); // Additional data is mixed into every CTR-DRBG call to protect, as best we // can, against forks & VM clones. We do not over-read this information and @@ -384,7 +403,10 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len, // entropy is used. This can be expensive (one read per |RAND_bytes| call) // and so is disabled when we have fork detection, or if the application has // promised not to fork. - if (fork_generation != 0 || rand_fork_unsafe_buffering_enabled()) { + // snapsafe_status is only 0 when the kernel has snapsafe support, but it + // failed to initialize. Otherwise, snapsafe_status is 1. + if ((snapsafe_status != 0 && fork_generation != 0) || + fork_unsafe_buffering) { OPENSSL_memset(additional_data, 0, sizeof(additional_data)); } else if (!have_rdrand()) { // No alternative so block for OS entropy. @@ -439,6 +461,8 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len, } state->calls = 0; state->fork_generation = fork_generation; + state->fork_unsafe_buffering = fork_unsafe_buffering; + state->snapsafe_generation = snapsafe_generation; #if defined(BORINGSSL_FIPS) if (state != &stack_state) { @@ -458,7 +482,16 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len, } if (state->calls >= kReseedInterval || - state->fork_generation != fork_generation) { + // If we've been cloned since |state| was last seeded, reseed. + state->snapsafe_generation != snapsafe_generation || + // If we've forked since |state| was last seeded, reseed. + state->fork_generation != fork_generation || + // If |state| was seeded from a state with different fork-safety + // preferences, reseed. Suppose |state| was fork-safe, then forked into + // two children, but each of the children never fork and disable fork + // safety. The children must reseed to avoid working from the same PRNG + // state. + state->fork_unsafe_buffering != fork_unsafe_buffering) { uint8_t seed[CTR_DRBG_ENTROPY_LEN]; int want_additional_input; rand_get_seed(state, seed, &want_additional_input); @@ -485,6 +518,8 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len, } state->calls = 0; state->fork_generation = fork_generation; + state->fork_unsafe_buffering = fork_unsafe_buffering; + state->snapsafe_generation = snapsafe_generation; OPENSSL_cleanse(seed, CTR_DRBG_ENTROPY_LEN); OPENSSL_cleanse(add_data_for_reseed, CTR_DRBG_ENTROPY_LEN); } else { @@ -518,6 +553,20 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len, } OPENSSL_cleanse(additional_data, 32); +#if !defined(AWSLC_SNAPSAFE_TESTING) + // SysGenId tests might be running parallel to this, causing changes to sgn. + if (1 == CRYPTO_get_snapsafe_generation(&snapsafe_generation)) { + if (snapsafe_generation != state->snapsafe_generation) { + // Unexpected change to snapsafe generation. + // A change in the snapsafe generation between the beginning of this + // funtion and here indicates that a snapshot was taken (and is now being + // used) while this function was executing. This is an invalid snapshot + // and is not safe for use. Please ensure all processing is completed + // prior to collecting a snapshot. + abort(); + } + } +#endif #if defined(BORINGSSL_FIPS) CRYPTO_STATIC_MUTEX_unlock_read(state_clear_all_lock_bss_get()); diff --git a/crypto/fipsmodule/rand/snapsafe_detect.c b/crypto/fipsmodule/rand/snapsafe_detect.c new file mode 100644 index 0000000000..7248805593 --- /dev/null +++ b/crypto/fipsmodule/rand/snapsafe_detect.c @@ -0,0 +1,159 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include + +#include "snapsafe_detect.h" + +#if defined(OPENSSL_LINUX) +#include +#include +#include +#include +#include "../delocate.h" + +// Snapsafety state +#define SNAPSAFETY_STATE_FAILED_INITIALISE 0x00 +#define SNAPSAFETY_STATE_SUCCESS_INITIALISE 0x01 +#define SNAPSAFETY_STATE_NOT_SUPPORTED 0x02 + +DEFINE_STATIC_ONCE(aws_snapsafe_init) +DEFINE_BSS_GET(volatile uint32_t *, sgc_addr) +DEFINE_BSS_GET(int, snapsafety_state) + +// aws_snapsafe_check_kernel_support returns 1 if the special sysgenid device +// file exists and 0 otherwise. +static int aws_snapsafe_check_kernel_support(void) { + // This file-exist method is generally brittle. But for our purpose, this + // should be more than fine. + if (access(CRYPTO_get_sysgenid_path(), F_OK) != 0) { + return 0; + } + return 1; +} + +static void do_aws_snapsafe_init(void) { + *snapsafety_state_bss_get() = SNAPSAFETY_STATE_NOT_SUPPORTED; + *sgc_addr_bss_get() = NULL; + + if (aws_snapsafe_check_kernel_support() != 1) { + return; + } + *snapsafety_state_bss_get() = SNAPSAFETY_STATE_FAILED_INITIALISE; + + int fd_sgc = open(CRYPTO_get_sysgenid_path(), O_RDONLY); + if (fd_sgc == -1) { + return; + } + + void *addr = mmap(NULL, sizeof(uint32_t), PROT_READ, MAP_SHARED, fd_sgc, 0); + + // Can close file descriptor now per + // https://man7.org/linux/man-pages/man2/mmap.2.html: "After the mmap() call + // has returned, the file descriptor, fd, can be closed immediately without + // invalidating the mapping.". We have initialised snapsafety without errors + // and this function is only executed once. Therefore, try to close file + // descriptor but don't error if it fails. */ + close(fd_sgc); + + if (addr == MAP_FAILED) { + return; + } + + // sgc_addr will now point at the mapped memory and any 4-byte read from + // this pointer will correspond to the sgn managed by the VMM. + *sgc_addr_bss_get() = addr; + *snapsafety_state_bss_get() = SNAPSAFETY_STATE_SUCCESS_INITIALISE; +} + +static uint32_t aws_snapsafe_read_sgn(void) { + if (*snapsafety_state_bss_get() == SNAPSAFETY_STATE_SUCCESS_INITIALISE) { + return **sgc_addr_bss_get(); + } + + return 0; +} + +int CRYPTO_get_snapsafe_generation(uint32_t *snapsafe_generation_number) { + CRYPTO_once(aws_snapsafe_init_bss_get(), do_aws_snapsafe_init); + + int state = *snapsafety_state_bss_get(); + switch (state) { + case SNAPSAFETY_STATE_NOT_SUPPORTED: + *snapsafe_generation_number = 0; + return 1; + case SNAPSAFETY_STATE_SUCCESS_INITIALISE: + *snapsafe_generation_number = aws_snapsafe_read_sgn(); + return 1; + case SNAPSAFETY_STATE_FAILED_INITIALISE: + *snapsafe_generation_number = 0; + return 0; + default: + // No other state should be possible. + abort(); + } +} + +int CRYPTO_get_snapsafe_active(void) { + CRYPTO_once(aws_snapsafe_init_bss_get(), do_aws_snapsafe_init); + + if (*snapsafety_state_bss_get() == SNAPSAFETY_STATE_SUCCESS_INITIALISE) { + return 1; + } + + return 0; +} + +int CRYPTO_get_snapsafe_supported(void) { + CRYPTO_once(aws_snapsafe_init_bss_get(), do_aws_snapsafe_init); + + if (*snapsafety_state_bss_get() == SNAPSAFETY_STATE_NOT_SUPPORTED) { + return 0; + } + + return 1; +} + +#else // !defined(OPENSSL_LINUX) + +int CRYPTO_get_snapsafe_generation(uint32_t *snapsafe_generation_number) { + *snapsafe_generation_number = 0; + return 1; +} + +int CRYPTO_get_snapsafe_active(void) { return 0; } + +int CRYPTO_get_snapsafe_supported(void) { return 0; } + +#endif // defined(OPENSSL_LINUX) + +const char* CRYPTO_get_sysgenid_path(void) { + return AWSLC_SYSGENID_PATH; +} + +#if defined(OPENSSL_LINUX) && defined(AWSLC_SNAPSAFE_TESTING) +int HAZMAT_init_sysgenid_file(void) { + int fd_sgn = open(CRYPTO_get_sysgenid_path(), O_CREAT | O_RDWR, S_IRWXU | S_IRGRP | S_IROTH); + if (fd_sgn == -1) { + return 0; + } + if (0 != lseek(fd_sgn, 0, SEEK_SET)) { + close(fd_sgn); + return 0; + } + uint32_t value = 0; + if(0 >= write(fd_sgn, &value, sizeof(uint32_t))) { + close(fd_sgn); + return 0; + } + + if (0 != fsync(fd_sgn)) { + close(fd_sgn); + return 0; + } + + close(fd_sgn); + + return 1; +} +#endif diff --git a/crypto/fipsmodule/rand/snapsafe_detect.h b/crypto/fipsmodule/rand/snapsafe_detect.h new file mode 100644 index 0000000000..db89a87297 --- /dev/null +++ b/crypto/fipsmodule/rand/snapsafe_detect.h @@ -0,0 +1,59 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef HEADER_SNAPSAFE_DETECT +#define HEADER_SNAPSAFE_DETECT + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(AWSLC_SYSGENID_PATH) + #define AWSLC_SYSGENID_PATH "/dev/sysgenid" +#endif + +// Snapsafe-type uniqueness breaking event (ube detection). +// +// CRYPTO_get_snapsafe_generation provides the snapsafe generation number for +// the current process. The snapsafe generation number is a non-zero, +// strictly-monotonic counter with the property that, if queried in an address +// space and then again in a subsequently resumed snapshot/VM, the resumed +// address space will observe a greater value. +// +// We use SysGenID to detect resumed snapshot/VM events. See +// https://lkml.org/lkml/2021/3/8/677 for details about how SysGenID works. +// We make light use of the SysGenId capabilities and only use the following +// supported functions on the device: |open| and |mmap|. +// +// |CRYPTO_get_snapsafe_generation| returns 0 only when the filesystem +// presents SysGenID interface (default is `/dev/sysgenid`) but we are +// is unable to initialize its use. Otherwise, it returns 1. +OPENSSL_EXPORT int CRYPTO_get_snapsafe_generation( + uint32_t *snapsafe_generation_number); + +// CRYPTO_get_snapsafe_active returns 1 if the file system presents the SysGenID +// interface and the libraruy has successfully initialized its use. Otherwise, +// it returns 0. +OPENSSL_EXPORT int CRYPTO_get_snapsafe_active(void); + +// CRYPTO_get_snapsafe_supported returns 1 if the file system presents the +// SysGenID interface. Otherwise, it returns 0. +OPENSSL_EXPORT int CRYPTO_get_snapsafe_supported(void); + +// CRYPTO_get_sysgenid_path returns the path used for the SysGenId interface. +OPENSSL_EXPORT const char *CRYPTO_get_sysgenid_path(void); + +#if defined(OPENSSL_LINUX) && defined(AWSLC_SNAPSAFE_TESTING) +// HAZMAT_init_sysgenid_file should only be used for testing. It creates and +// initializes the sysgenid path indicated by AWSLC_SYSGENID_PATH. +// On success, it returns 1. Otherwise, returns 0. +OPENSSL_EXPORT int HAZMAT_init_sysgenid_file(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_SNAPSAFE_DETECT */ diff --git a/crypto/fipsmodule/rand/snapsafe_detect_test.cc b/crypto/fipsmodule/rand/snapsafe_detect_test.cc new file mode 100644 index 0000000000..666b8e9539 --- /dev/null +++ b/crypto/fipsmodule/rand/snapsafe_detect_test.cc @@ -0,0 +1,115 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include +#include + +#include +#include "snapsafe_detect.h" + +#if defined(OPENSSL_LINUX) && defined(AWSLC_SNAPSAFE_TESTING) +#include +#include +#include + +#define NUMBER_OF_TEST_VALUES 5 + +typedef struct sgn_test_s { + void *addr; +} sgn_test_s; + +static int init_sgn_file(void** addr); +static int init_sgn_file(void** addr) { + *addr = nullptr; + + // This file should've been created during test initialization + const int fd_sgn = open(CRYPTO_get_sysgenid_path(), O_RDWR); + if (fd_sgn == -1) { + return 0; + } + + if (0 != lseek(fd_sgn, 0, SEEK_SET)) { + close(fd_sgn); + return 0; + } + + void* my_addr = mmap(nullptr, sizeof(uint32_t), PROT_WRITE, MAP_SHARED, fd_sgn, 0); + if (my_addr == MAP_FAILED) { + close(fd_sgn); + return 0; + } + + close(fd_sgn); + + *addr = my_addr; + + return 1; +} + +static int init_sgn_test(sgn_test_s* sgn_test); +static int init_sgn_test(sgn_test_s* sgn_test) { + return init_sgn_file(&sgn_test->addr); +} + +static int set_sgn(const sgn_test_s* sgn_test, uint32_t val); +static int set_sgn(const sgn_test_s* sgn_test, uint32_t val) { + memcpy(sgn_test->addr, &val, sizeof(uint32_t)); + if(0 != msync(sgn_test->addr, sizeof(uint32_t), MS_SYNC)) { + return 0; + } + return 1; +} + +TEST(SnapsafeGenerationTest, DISABLED_SysGenIDretrievalTesting) { + sgn_test_s sgn_test; + ASSERT_TRUE(init_sgn_test(&sgn_test)); + + ASSERT_TRUE(set_sgn(&sgn_test, 0)); + + EXPECT_EQ(1, CRYPTO_get_snapsafe_supported()); + EXPECT_EQ(1, CRYPTO_get_snapsafe_active()); + + uint32_t current_snapsafe_gen_num = 0; + ASSERT_TRUE(set_sgn(&sgn_test, 7)); + ASSERT_TRUE(CRYPTO_get_snapsafe_generation(¤t_snapsafe_gen_num)); + ASSERT_EQ((uint32_t) 7, current_snapsafe_gen_num); + + uint32_t test_sysgenid_values[NUMBER_OF_TEST_VALUES] = { + 0x03, // 2^0 + 2 + 0x103, // 2^8 + 3 + 0x10004, // 2^16 + 4 + 0x1000005, // 2^24 + 5 + 0xFFFFFFFF // 2^32 - 1 + }; + + for (size_t i = 0; i < NUMBER_OF_TEST_VALUES; i++) { + // Exercise all bytes of the 32-bit generation number. + uint32_t new_sysgenid_value_hint = test_sysgenid_values[i]; + ASSERT_TRUE(set_sgn(&sgn_test, new_sysgenid_value_hint)); + ASSERT_TRUE(CRYPTO_get_snapsafe_generation(¤t_snapsafe_gen_num)); + EXPECT_EQ(new_sysgenid_value_hint, current_snapsafe_gen_num); + } +} +#elif defined(OPENSSL_LINUX) +TEST(SnapsafeGenerationTest, SysGenIDretrievalLinux) { + uint32_t current_snapsafe_gen_num = 0xffffffff; + ASSERT_TRUE(CRYPTO_get_snapsafe_generation(¤t_snapsafe_gen_num)); + if (CRYPTO_get_snapsafe_supported()) { + ASSERT_TRUE(CRYPTO_get_snapsafe_active()); + // If we're on a system where the SysGenId is available, we won't + // know what sgn value to expect, but we assume it's not 0xffffffff + ASSERT_NE(0xffffffff, current_snapsafe_gen_num); + } else { + ASSERT_FALSE(CRYPTO_get_snapsafe_active()); + ASSERT_EQ((uint32_t) 0, current_snapsafe_gen_num); + } +} +#else +TEST(SnapsafeGenerationTest, SysGenIDretrievalNonLinux) { + ASSERT_FALSE(CRYPTO_get_snapsafe_supported()); + ASSERT_FALSE(CRYPTO_get_snapsafe_active()); + uint32_t current_snapsafe_gen_num = 0xffffffff; + ASSERT_TRUE(CRYPTO_get_snapsafe_generation(¤t_snapsafe_gen_num)); + ASSERT_EQ((uint32_t) 0, current_snapsafe_gen_num); +} +#endif // defined(OPENSSL_LINUX) diff --git a/crypto/fipsmodule/rand/urandom_test.cc b/crypto/fipsmodule/rand/urandom_test.cc index 2fe29b6929..b50f49df66 100644 --- a/crypto/fipsmodule/rand/urandom_test.cc +++ b/crypto/fipsmodule/rand/urandom_test.cc @@ -18,11 +18,13 @@ #include #include -#include "internal.h" #include "getrandom_fillin.h" +#include "internal.h" +#include "snapsafe_detect.h" #if defined(OPENSSL_X86_64) && !defined(BORINGSSL_SHARED_LIBRARY) && \ - !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && defined(USE_NR_getrandom) + !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && \ + defined(USE_NR_getrandom) && !defined(AWSLC_SNAPSAFE_TESTING) #include @@ -33,6 +35,11 @@ #include "fork_detect.h" +#include +#include +#include +#include + #if !defined(PTRACE_O_EXITKILL) #define PTRACE_O_EXITKILL (1 << 20) #endif @@ -268,7 +275,9 @@ static void GetTrace(std::vector *out_trace, unsigned flags, // valid pointer in our address space. const char *filename = reinterpret_cast( (syscall_number == __NR_openat) ? regs.rsi : regs.rdi); - out_trace->push_back(Event::Open(filename)); + if (strcmp(filename, CRYPTO_get_sysgenid_path()) != 0) { + out_trace->push_back(Event::Open(filename)); + } is_opening_urandom = strcmp(filename, "/dev/urandom") == 0; if (is_opening_urandom && (flags & NO_URANDOM)) { inject_error = -ENOENT; @@ -602,4 +611,4 @@ int main(int argc, char **argv) { } #endif // X86_64 && !SHARED_LIBRARY && !UNSAFE_DETERMINISTIC_MODE && - // USE_NR_getrandom + // USE_NR_getrandom && !AWSLC_SNAPSAFE_TESTING diff --git a/crypto/internal.h b/crypto/internal.h index cfed915f6f..e3ddfbeef2 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -115,6 +115,8 @@ #include #include +#include "fipsmodule/rand/snapsafe_detect.h" + #include #include diff --git a/crypto/test/gtest_main.cc b/crypto/test/gtest_main.cc index ffdf2720d1..9f1386e3ee 100644 --- a/crypto/test/gtest_main.cc +++ b/crypto/test/gtest_main.cc @@ -25,9 +25,14 @@ int main(int argc, char **argv) { +#if defined(OPENSSL_LINUX) && defined(AWSLC_SNAPSAFE_TESTING) + if (1 != HAZMAT_init_sysgenid_file()) { + abort(); + } +#endif + testing::InitGoogleTest(&argc, argv); bssl::SetupGoogleTest(); - bool unwind_tests = true; for (int i = 1; i < argc; i++) { #if !defined(OPENSSL_WINDOWS) diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 4b4edf92c9..af51178d38 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc @@ -1338,6 +1338,12 @@ class StderrDelimiter { }; int main(int argc, char **argv) { +#if defined(OPENSSL_LINUX) && defined(AWSLC_SNAPSAFE_TESTING) + if (1 != HAZMAT_init_sysgenid_file()) { + abort(); + } +#endif + // To distinguish ASan's output from ours, add a trailing message to stderr. // Anything following this line will be considered an error. StderrDelimiter delimiter; diff --git a/ssl/test/handshaker.cc b/ssl/test/handshaker.cc index ac890633d9..ae7341a92b 100644 --- a/ssl/test/handshaker.cc +++ b/ssl/test/handshaker.cc @@ -27,6 +27,7 @@ #include "handshake_util.h" #include "test_config.h" #include "test_state.h" +#include "../crypto/internal.h" using namespace bssl; @@ -223,6 +224,12 @@ int SignalError() { } // namespace int main(int argc, char **argv) { +#if defined(OPENSSL_LINUX) && defined(AWSLC_SNAPSAFE_TESTING) + if (1 != HAZMAT_init_sysgenid_file()) { + abort(); + } +#endif + TestConfig initial_config, resume_config, retry_config; if (!ParseConfig(argc - 1, argv + 1, /*is_shim=*/false, &initial_config, &resume_config, &retry_config)) { diff --git a/tests/ci/run_fips_tests.sh b/tests/ci/run_fips_tests.sh index 6cce88fba9..ee8ce08381 100755 --- a/tests/ci/run_fips_tests.sh +++ b/tests/ci/run_fips_tests.sh @@ -20,6 +20,11 @@ if [[ ("$(uname -s)" == 'Linux'*) && (("$(uname -p)" == 'x86_64'*) || ("$(uname echo "Testing AWS-LC static library in FIPS Release mode with FIPS entropy source method CPU Jitter." fips_build_and_test -DCMAKE_BUILD_TYPE=Release -DENABLE_FIPS_ENTROPY_CPU_JITTER=ON + + echo "Testing AWS-LC static library in FIPS Debug with SysGenId." + TEST_SYSGENID_PATH=$(mktemp) + dd if=/dev/zero of="${TEST_SYSGENID_PATH}" bs=1 count=4096 + fips_build_and_test -DTEST_SYSGENID_PATH="${TEST_SYSGENID_PATH}" fi # The AL2 version of Clang does not have all of the required artifacts for address sanitizer, see P45594051 diff --git a/tests/ci/run_posix_tests.sh b/tests/ci/run_posix_tests.sh index 0ac68291f9..0d916e88a3 100755 --- a/tests/ci/run_posix_tests.sh +++ b/tests/ci/run_posix_tests.sh @@ -1,8 +1,9 @@ -#!/bin/bash -set -exo pipefail +#!/usr/bin/env bash # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 OR ISC +set -exo pipefail + source tests/ci/common_posix_setup.sh print_system_and_dependency_information @@ -28,6 +29,11 @@ if [[ "${AWSLC_FIPS}" == "1" ]]; then "${BUILD_ROOT}/util/fipstools/test_fips" fi +echo "Testing building with a SysGenId." +TEST_SYSGENID_PATH=$(mktemp) +dd if=/dev/zero of="${TEST_SYSGENID_PATH}" bs=1 count=4096 +build_and_test -DTEST_SYSGENID_PATH="${TEST_SYSGENID_PATH}" + if [[ "${AWSLC_C99_TEST}" == "1" ]]; then echo "Testing the C99 compatability of AWS-LC headers." ./tests/coding_guidelines/c99_gcc_test.sh diff --git a/util/all_tests.json b/util/all_tests.json index 77c6c55267..a94ce610c8 100644 --- a/util/all_tests.json +++ b/util/all_tests.json @@ -44,6 +44,12 @@ "skip_valgrind": true, "target_arch": "x86" }, + { + "comment": "Run snapsafe detection test suite", + "cmd": ["crypto/crypto_test", "--gtest_also_run_disabled_tests", "--gtest_filter=SnapsafeGenerationTest.*"], + "skip_valgrind": true, + "shard": false + }, { "comment": "Potentially with RDRAND, but not Intel", "cmd": ["crypto/urandom_test"],