diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2022-07-09 10:40:08 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2022-07-09 10:40:08 +0300 |
commit | 22acf19be42357b6bb0e7d601b0dc28695191463 (patch) | |
tree | a35a222fffb28fcf8a82dd7efe67f2276bfd1858 /contrib/restricted/aws/s2n/utils/s2n_random.c | |
parent | 7a7d303e197aa7e4f43c61cc289d8652df38ab43 (diff) | |
download | ydb-22acf19be42357b6bb0e7d601b0dc28695191463.tar.gz |
Update contrib/restricted/aws/s2n to 1.3.16
Diffstat (limited to 'contrib/restricted/aws/s2n/utils/s2n_random.c')
-rw-r--r-- | contrib/restricted/aws/s2n/utils/s2n_random.c | 180 |
1 files changed, 91 insertions, 89 deletions
diff --git a/contrib/restricted/aws/s2n/utils/s2n_random.c b/contrib/restricted/aws/s2n/utils/s2n_random.c index 295c87006f..9c0efc0f9f 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_random.c +++ b/contrib/restricted/aws/s2n/utils/s2n_random.c @@ -14,6 +14,7 @@ */ #include <openssl/engine.h> +#include <openssl/rand.h> #include <sys/types.h> #include <sys/stat.h> @@ -28,25 +29,20 @@ #include <errno.h> #include <time.h> -#include "api/s2n.h" - #if defined(S2N_CPUID_AVAILABLE) #include <cpuid.h> #endif -#include "stuffer/s2n_stuffer.h" - +#include "api/s2n.h" #include "crypto/s2n_drbg.h" - #include "error/s2n_errno.h" - +#include "stuffer/s2n_stuffer.h" +#include "utils/s2n_fork_detection.h" #include "utils/s2n_result.h" #include "utils/s2n_safety.h" #include "utils/s2n_random.h" #include "utils/s2n_mem.h" -#include <openssl/rand.h> - #define ENTROPY_SOURCE "/dev/urandom" /* See https://en.wikipedia.org/wiki/CPUID */ @@ -60,14 +56,19 @@ static int entropy_fd = UNINITIALIZED_ENTROPY_FD; -static __thread struct s2n_drbg per_thread_private_drbg = {0}; -static __thread struct s2n_drbg per_thread_public_drbg = {0}; - -static void *zeroed_when_forked_page = NULL; -static int zero = 0; +struct s2n_rand_state { + uint64_t cached_fork_generation_number; + struct s2n_drbg public_drbg; + struct s2n_drbg private_drbg; + bool drbgs_initialized; +}; -static __thread void *zero_if_forked_ptr = &zero; -#define zero_if_forked (* (int *) zero_if_forked_ptr) +static __thread struct s2n_rand_state s2n_per_thread_rand_state = { + .cached_fork_generation_number = 0, + .public_drbg = {0}, + .private_drbg = {0}, + .drbgs_initialized = false +}; static int s2n_rand_init_impl(void); static int s2n_rand_cleanup_impl(void); @@ -79,6 +80,7 @@ static s2n_rand_cleanup_callback s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; static s2n_rand_seed_callback s2n_rand_seed_cb = s2n_rand_urandom_impl; static s2n_rand_mix_callback s2n_rand_mix_cb = s2n_rand_urandom_impl; +/* non-static for SAW proof */ bool s2n_cpu_supports_rdrand() { #if defined(S2N_CPUID_AVAILABLE) uint32_t eax, ebx, ecx, edx; @@ -128,65 +130,74 @@ S2N_RESULT s2n_get_mix_entropy(struct s2n_blob *blob) return S2N_RESULT_OK; } -void s2n_on_fork(void) -{ - zero_if_forked = 0; -} - -static inline S2N_RESULT s2n_defend_if_forked(void) +static S2N_RESULT s2n_init_drbgs(void) { uint8_t s2n_public_drbg[] = "s2n public drbg"; uint8_t s2n_private_drbg[] = "s2n private drbg"; - struct s2n_blob public = {.data = s2n_public_drbg,.size = sizeof(s2n_public_drbg) }; - struct s2n_blob private = {.data = s2n_private_drbg,.size = sizeof(s2n_private_drbg) }; + struct s2n_blob public = { .data = s2n_public_drbg, .size = sizeof(s2n_public_drbg) }; + struct s2n_blob private = { .data = s2n_private_drbg, .size = sizeof(s2n_private_drbg) }; - if (zero_if_forked == 0) { - /* Clean up the old drbg first */ - RESULT_GUARD(s2n_rand_cleanup_thread()); - /* Instantiate the new ones */ - RESULT_GUARD(s2n_drbg_instantiate(&per_thread_public_drbg, &public, S2N_AES_128_CTR_NO_DF_PR)); - RESULT_GUARD(s2n_drbg_instantiate(&per_thread_private_drbg, &private, S2N_AES_128_CTR_NO_DF_PR)); - zero_if_forked_ptr = zeroed_when_forked_page; - zero_if_forked = 1; - } + RESULT_GUARD(s2n_drbg_instantiate(&s2n_per_thread_rand_state.public_drbg, &public, S2N_AES_128_CTR_NO_DF_PR)); + RESULT_GUARD(s2n_drbg_instantiate(&s2n_per_thread_rand_state.private_drbg, &private, S2N_AES_256_CTR_NO_DF_PR)); + + s2n_per_thread_rand_state.drbgs_initialized = true; return S2N_RESULT_OK; } -S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob) +static S2N_RESULT s2n_ensure_initialized_drbgs(void) { - RESULT_GUARD(s2n_defend_if_forked()); + if (s2n_per_thread_rand_state.drbgs_initialized == false) { + RESULT_GUARD(s2n_init_drbgs()); - uint32_t offset = 0; - uint32_t remaining = blob->size; + /* Then cache the fork generation number. We just initialized the drbg + * states with new entropy and forking is not an external event. + */ + uint64_t returned_fork_generation_number = 0; + RESULT_GUARD(s2n_get_fork_generation_number(&returned_fork_generation_number)); + s2n_per_thread_rand_state.cached_fork_generation_number = returned_fork_generation_number; + } - while(remaining) { - struct s2n_blob slice = { 0 }; + return S2N_RESULT_OK; +} - RESULT_GUARD_POSIX(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; +/* s2n_ensure_uniqueness() implements defenses against uniqueness + * breaking events that might cause duplicated drbg states. Currently, only + * implements fork detection. + */ +static S2N_RESULT s2n_ensure_uniqueness(void) +{ + uint64_t returned_fork_generation_number = 0; + RESULT_GUARD(s2n_get_fork_generation_number(&returned_fork_generation_number)); - RESULT_GUARD(s2n_drbg_generate(&per_thread_public_drbg, &slice)); + if (returned_fork_generation_number != s2n_per_thread_rand_state.cached_fork_generation_number) { - remaining -= slice.size; - offset += slice.size; + /* This assumes that s2n_rand_cleanup_thread() doesn't mutate any other + * state than the drbg states and it resets the drbg initialization + * boolean to false. s2n_ensure_initialized_drbgs() will cache the new + * fork generation number in the per thread state. + */ + RESULT_GUARD(s2n_rand_cleanup_thread()); + RESULT_GUARD(s2n_ensure_initialized_drbgs()); } return S2N_RESULT_OK; } -S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) +static S2N_RESULT s2n_get_random_data(struct s2n_blob *out_blob, + struct s2n_drbg *drbg_state) { - RESULT_GUARD(s2n_defend_if_forked()); + RESULT_GUARD(s2n_ensure_initialized_drbgs()); + RESULT_GUARD(s2n_ensure_uniqueness()); uint32_t offset = 0; - uint32_t remaining = blob->size; + uint32_t remaining = out_blob->size; while(remaining) { struct s2n_blob slice = { 0 }; - RESULT_GUARD_POSIX(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; - - RESULT_GUARD(s2n_drbg_generate(&per_thread_private_drbg, &slice)); + RESULT_GUARD_POSIX(s2n_blob_slice(out_blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT))); + RESULT_GUARD(s2n_drbg_generate(drbg_state, &slice)); remaining -= slice.size; offset += slice.size; @@ -195,15 +206,29 @@ S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) return S2N_RESULT_OK; } +S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob) +{ + RESULT_GUARD(s2n_get_random_data(blob, &s2n_per_thread_rand_state.public_drbg)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) +{ + RESULT_GUARD(s2n_get_random_data(blob, &s2n_per_thread_rand_state.private_drbg)); + + return S2N_RESULT_OK; +} + S2N_RESULT s2n_get_public_random_bytes_used(uint64_t *bytes_used) { - RESULT_GUARD(s2n_drbg_bytes_used(&per_thread_public_drbg, bytes_used)); + RESULT_GUARD(s2n_drbg_bytes_used(&s2n_per_thread_rand_state.public_drbg, bytes_used)); return S2N_RESULT_OK; } S2N_RESULT s2n_get_private_random_bytes_used(uint64_t *bytes_used) { - RESULT_GUARD(s2n_drbg_bytes_used(&per_thread_private_drbg, bytes_used)); + RESULT_GUARD(s2n_drbg_bytes_used(&s2n_per_thread_rand_state.private_drbg, bytes_used)); return S2N_RESULT_OK; } @@ -328,7 +353,7 @@ static int s2n_rand_init_impl(void) { OPEN: entropy_fd = open(ENTROPY_SOURCE, O_RDONLY); - if (entropy_fd == S2N_FAILURE) { + if (entropy_fd == -1) { if (errno == EINTR) { goto OPEN; } @@ -344,33 +369,9 @@ static int s2n_rand_init_impl(void) S2N_RESULT s2n_rand_init(void) { - uint32_t pagesize; - RESULT_GUARD_POSIX(s2n_rand_init_cb()); - pagesize = s2n_mem_get_page_size(); - - /* We need a single-aligned page for our protected memory region */ - RESULT_ENSURE(posix_memalign(&zeroed_when_forked_page, pagesize, pagesize) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); - RESULT_ENSURE(zeroed_when_forked_page != NULL, S2N_ERR_OPEN_RANDOM); - - /* Initialized to zero to ensure that we seed our DRBGs */ - zero_if_forked = 0; - - /* INHERIT_ZERO and WIPEONFORK reset a page to all-zeroes when a fork occurs */ -#if defined(MAP_INHERIT_ZERO) - RESULT_ENSURE(minherit(zeroed_when_forked_page, pagesize, MAP_INHERIT_ZERO) != S2N_FAILURE, S2N_ERR_OPEN_RANDOM); -#endif - -#if defined(MADV_WIPEONFORK) - RESULT_ENSURE(madvise(zeroed_when_forked_page, pagesize, MADV_WIPEONFORK) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); -#endif - - /* For defence in depth */ - RESULT_ENSURE(pthread_atfork(NULL, NULL, s2n_on_fork) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); - - /* Seed everything */ - RESULT_GUARD(s2n_defend_if_forked()); + RESULT_GUARD(s2n_ensure_initialized_drbgs()); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Create an engine */ @@ -423,12 +424,6 @@ S2N_RESULT s2n_rand_cleanup(void) } #endif - if (zeroed_when_forked_page != NULL) { - free(zeroed_when_forked_page); - zeroed_when_forked_page = NULL; - zero_if_forked_ptr = &zero; - } - s2n_rand_init_cb = s2n_rand_init_impl; s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; s2n_rand_seed_cb = s2n_rand_urandom_impl; @@ -439,22 +434,29 @@ S2N_RESULT s2n_rand_cleanup(void) S2N_RESULT s2n_rand_cleanup_thread(void) { - RESULT_GUARD(s2n_drbg_wipe(&per_thread_private_drbg)); - RESULT_GUARD(s2n_drbg_wipe(&per_thread_public_drbg)); + /* Currently, it is only safe for this function to mutate the drbg states + * in the per thread rand state. See s2n_ensure_uniqueness(). + */ + RESULT_GUARD(s2n_drbg_wipe(&s2n_per_thread_rand_state.private_drbg)); + RESULT_GUARD(s2n_drbg_wipe(&s2n_per_thread_rand_state.public_drbg)); + + s2n_per_thread_rand_state.drbgs_initialized = false; return S2N_RESULT_OK; } -/* - * This must only be used for unit tests. Any real use is dangerous and will be overwritten in s2n_defend_if_forked if - * it is forked. This was added to support known answer tests that use OpenSSL and s2n_get_private_random_data directly. +/* This must only be used for unit tests. Any real use is dangerous and will be + * overwritten in s2n_ensure_uniqueness() if it is forked. This was added to + * support known answer tests that use OpenSSL and s2n_get_private_random_data + * directly. */ S2N_RESULT s2n_set_private_drbg_for_test(struct s2n_drbg drbg) { RESULT_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); - RESULT_GUARD(s2n_drbg_wipe(&per_thread_private_drbg)); + RESULT_GUARD(s2n_drbg_wipe(&s2n_per_thread_rand_state.private_drbg)); + + s2n_per_thread_rand_state.private_drbg = drbg; - per_thread_private_drbg = drbg; return S2N_RESULT_OK; } |