aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/s2n/utils/s2n_random.c
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2022-07-09 10:40:08 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2022-07-09 10:40:08 +0300
commit22acf19be42357b6bb0e7d601b0dc28695191463 (patch)
treea35a222fffb28fcf8a82dd7efe67f2276bfd1858 /contrib/restricted/aws/s2n/utils/s2n_random.c
parent7a7d303e197aa7e4f43c61cc289d8652df38ab43 (diff)
downloadydb-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.c180
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;
}