From 08a65d9686b131cb4193feaaf1d5cef941fa349c Mon Sep 17 00:00:00 2001 From: "Dr. Matthias St. Pierre" Date: Fri, 24 Nov 2017 15:24:51 +0100 Subject: [PATCH] Implement automatic reseeding of DRBG after a specified time interval Every DRBG now supports automatic reseeding not only after a given number of generate requests, but also after a specified time interval. Signed-off-by: Dr. Matthias St. Pierre Reviewed-by: Paul Dale Reviewed-by: Kurt Roeckx (Merged from https://github.com/openssl/openssl/pull/4402) --- crypto/rand/drbg_lib.c | 59 +++++++++++++++++++++++++++++++---------- crypto/rand/rand_lcl.h | 14 +++++++++- include/internal/rand.h | 1 + test/drbgtest.c | 13 +++++++++ util/libcrypto.num | 1 + 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c index 67a79d4efe..13dce3057c 100644 --- a/crypto/rand/drbg_lib.c +++ b/crypto/rand/drbg_lib.c @@ -72,18 +72,24 @@ static RAND_DRBG drbg_private; * * AUTOMATIC RESEEDING * - * Before satisfying a generate request, a DRBG reseeds itself automatically - * if the number of generate requests since the last reseeding exceeds a - * certain threshold, the so called |reseed_interval|. This automatic - * reseeding can be disabled by setting the |reseed_interval| to 0. + * Before satisfying a generate request, a DRBG reseeds itself automatically, + * if one of the following two conditions holds: + * + * - the number of generate requests since the last reseeding exceeds a + * certain threshold, the so called |reseed_interval|. This behaviour + * can be disabled by setting the |reseed_interval| to 0. + * + * - the time elapsed since the last reseeding exceeds a certain time + * interval, the so called |reseed_time_interval|. This behaviour + * can be disabled by setting the |reseed_time_interval| to 0. * * MANUAL RESEEDING * - * For the three shared DRBGs (and only for these) there is a way to reseed - * them manually by calling RAND_seed() (or RAND_add() with a positive + * For the three shared DRBGs (and only for these) there is another way to + * reseed them manually by calling RAND_seed() (or RAND_add() with a positive * |randomness| argument). This will immediately reseed the DRBG. - * Its immediate children ( and DRBG) will detect this - * on their next generate call and reseed, pulling randomness from . + * The and DRBG will detect this on their next generate + * call and reseed, pulling randomness from . */ @@ -222,7 +228,7 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg, drbg->state = DRBG_READY; drbg->generate_counter = 0; - + drbg->reseed_time = time(NULL); if (drbg->reseed_counter > 0) { if (drbg->parent == NULL) drbg->reseed_counter++; @@ -304,7 +310,7 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg, drbg->state = DRBG_READY; drbg->generate_counter = 0; - + drbg->reseed_time = time(NULL); if (drbg->reseed_counter > 0) { if (drbg->parent == NULL) drbg->reseed_counter++; @@ -475,7 +481,12 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, if (drbg->generate_counter >= drbg->reseed_interval) reseed_required = 1; } - + if (drbg->reseed_time_interval > 0) { + time_t now = time(NULL); + if (now < drbg->reseed_time + || now - drbg->reseed_time >= drbg->reseed_time_interval) + reseed_required = 1; + } if (drbg->reseed_counter > 0 && drbg->parent != NULL) { if (drbg->reseed_counter != drbg->parent->reseed_counter) reseed_required = 1; @@ -559,7 +570,7 @@ int RAND_DRBG_set_callbacks(RAND_DRBG *drbg, * * The drbg will reseed automatically whenever the number of generate * requests exceeds the given reseed interval. If the reseed interval - * is 0, then this automatic reseeding is disabled. + * is 0, then this feature is disabled. * * Returns 1 on success, 0 on failure. */ @@ -571,6 +582,24 @@ int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval) return 1; } +/* + * Set the reseed time interval. + * + * The drbg will reseed automatically whenever the time elapsed since + * the last reseeding exceeds the given reseed time interval. For safety, + * a reseeding will also occur if the clock has been reset to a smaller + * value. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval) +{ + if (interval > MAX_RESEED_TIME_INTERVAL) + return 0; + drbg->reseed_time_interval = interval; + return 1; +} + /* * Get and set the EXDATA */ @@ -616,11 +645,13 @@ static int drbg_setup(RAND_DRBG *drbg, const char *name, RAND_DRBG *parent) ret &= RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy, rand_drbg_cleanup_entropy, NULL, NULL) == 1; - if (parent == NULL) + if (parent == NULL) { drbg->reseed_interval = MASTER_RESEED_INTERVAL; - else { + drbg->reseed_time_interval = MASTER_RESEED_TIME_INTERVAL; + } else { drbg->parent = parent; drbg->reseed_interval = SLAVE_RESEED_INTERVAL; + drbg->reseed_time_interval = SLAVE_RESEED_TIME_INTERVAL; } /* enable seed propagation */ diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h index ad79434ec4..9044981bbb 100644 --- a/crypto/rand/rand_lcl.h +++ b/crypto/rand/rand_lcl.h @@ -20,12 +20,17 @@ /* How many times to read the TSC as a randomness source. */ # define TSC_READ_COUNT 4 -/* Maximum reseed interval */ +/* Maximum reseed intervals */ # define MAX_RESEED_INTERVAL (1 << 24) +# define MAX_RESEED_TIME_INTERVAL (1 << 20) /* approx. 12 days */ /* Default reseed intervals */ # define MASTER_RESEED_INTERVAL (1 << 8) # define SLAVE_RESEED_INTERVAL (1 << 16) +# define MASTER_RESEED_TIME_INTERVAL (60*60) /* 1 hour */ +# define SLAVE_RESEED_TIME_INTERVAL (7*60) /* 7 minutes */ + + /* Max size of additional input and personalization string. */ # define DRBG_MAX_LENGTH 4096 @@ -118,6 +123,13 @@ struct rand_drbg_st { * This value is ignored if it is zero. */ unsigned int reseed_interval; + /* Stores the time when the last reseeding occurred */ + time_t reseed_time; + /* + * Specifies the maximum time interval (in seconds) between reseeds. + * This value is ignored if it is zero. + */ + time_t reseed_time_interval; /* * Counts the number of reseeds since instantiation. * This value is ignored if it is zero. diff --git a/include/internal/rand.h b/include/internal/rand.h index 26d6c38f45..2f9a8015be 100644 --- a/include/internal/rand.h +++ b/include/internal/rand.h @@ -43,6 +43,7 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, int prediction_resistance, const unsigned char *adin, size_t adinlen); int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval); +int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval); RAND_DRBG *RAND_DRBG_get0_master(void); RAND_DRBG *RAND_DRBG_get0_public(void); diff --git a/test/drbgtest.c b/test/drbgtest.c index b1fc751cd9..68c169793c 100644 --- a/test/drbgtest.c +++ b/test/drbgtest.c @@ -573,6 +573,7 @@ static int test_drbg_reseed(int expect_success, ) { unsigned char buf[32]; + time_t before_reseed, after_reseed; int expected_state = (expect_success ? DRBG_READY : DRBG_ERROR); /* @@ -595,9 +596,11 @@ static int test_drbg_reseed(int expect_success, */ /* Generate random output from the public and private DRBG */ + before_reseed = expect_master_reseed == 1 ? time(NULL) : 0; if (!TEST_int_eq(RAND_bytes(buf, sizeof(buf)), expect_success) || !TEST_int_eq(RAND_priv_bytes(buf, sizeof(buf)), expect_success)) return 0; + after_reseed = time(NULL); /* @@ -633,6 +636,16 @@ static int test_drbg_reseed(int expect_success, if (!TEST_int_eq(public->reseed_counter, master->reseed_counter) || !TEST_int_eq(private->reseed_counter, master->reseed_counter)) return 0; + + /* Test whether reseed time of master DRBG is set correctly */ + if (!TEST_time_t_le(before_reseed, master->reseed_time) + || !TEST_time_t_le(master->reseed_time, after_reseed)) + return 0; + + /* Test whether reseed times of child DRBGs are synchronized with master */ + if (!TEST_time_t_ge(public->reseed_time, master->reseed_time) + || !TEST_time_t_ge(private->reseed_time, master->reseed_time)) + return 0; } else { ERR_clear_error(); } diff --git a/util/libcrypto.num b/util/libcrypto.num index 7bfa6015d0..0b52a446cc 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4447,3 +4447,4 @@ RSA_get_version 4391 1_1_1 EXIST::FUNCTION:RSA RSA_meth_get_multi_prime_keygen 4392 1_1_1 EXIST::FUNCTION:RSA RSA_meth_set_multi_prime_keygen 4393 1_1_1 EXIST::FUNCTION:RSA RAND_DRBG_get0_master 4394 1_1_1 EXIST::FUNCTION: +RAND_DRBG_set_reseed_time_interval 4395 1_1_1 EXIST::FUNCTION: -- 2.25.1