Implement automatic reseeding of DRBG after a specified time interval
authorDr. Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>
Fri, 24 Nov 2017 14:24:51 +0000 (15:24 +0100)
committerDr. Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>
Sun, 17 Dec 2017 22:12:10 +0000 (23:12 +0100)
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 <Matthias.St.Pierre@ncp-e.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Kurt Roeckx <kurt@roeckx.be>
(Merged from https://github.com/openssl/openssl/pull/4402)

crypto/rand/drbg_lib.c
crypto/rand/rand_lcl.h
include/internal/rand.h
test/drbgtest.c
util/libcrypto.num

index 67a79d4..13dce30 100644 (file)
@@ -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 <master> DRBG.
- * Its immediate children (<public> and <private> DRBG) will detect this
- * on their next generate call and reseed, pulling randomness from <master>.
+ * The <public> and <private> DRBG will detect this on their next generate
+ * call and reseed, pulling randomness from <master>.
  */
 
 
@@ -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 */
index ad79434..9044981 100644 (file)
 /* 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.
index 26d6c38..2f9a801 100644 (file)
@@ -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);
index b1fc751..68c1697 100644 (file)
@@ -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();
     }
index 7bfa601..0b52a44 100644 (file)
@@ -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: