[openssl-commits] [openssl] OpenSSL_1_1_1-stable update

matthias.st.pierre at ncp-e.com matthias.st.pierre at ncp-e.com
Sat Oct 27 11:05:17 UTC 2018


The branch OpenSSL_1_1_1-stable has been updated
       via  1f98527659b8290d442c4e1532452b9ba6463f1e (commit)
       via  d597a9a877f4e5b0b3803a1bb05b30b34b4be699 (commit)
       via  35a34508ef4d649ace4e373e1d019192b7e38c36 (commit)
      from  0b3f5eab644dfcb7023b2396ec0c9aa6785f48e2 (commit)


- Log -----------------------------------------------------------------
commit 1f98527659b8290d442c4e1532452b9ba6463f1e
Author: Bernd Edlinger <bernd.edlinger at hotmail.de>
Date:   Sun Oct 14 12:35:19 2018 +0200

    Fix data race in RAND_DRBG_generate
    
    Fixes #7394
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/7399)
    
    (cherry picked from commit a83dc59afa2e0207180d7218efed19b20d48de95)

commit d597a9a877f4e5b0b3803a1bb05b30b34b4be699
Author: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
Date:   Sun Oct 21 15:45:34 2018 +0200

    RAND_add()/RAND_seed(): fix failure on short input or low entropy
    
    Commit 5b4cb385c18a (#7382) introduced a bug which had the effect
    that RAND_add()/RAND_seed() failed for buffer sizes less than
    32 bytes. The reason was that now the added random data was used
    exlusively as entropy source for reseeding. When the random input
    was too short or contained not enough entropy, the DRBG failed
    without querying the available entropy sources.
    
    This commit makes drbg_add() act smarter: it checks the entropy
    requirements explicitely. If the random input fails this check,
    it won't be added as entropy input, but only as additional data.
    More precisely, the behaviour depends on whether an os entropy
    source was configured (which is the default on most os):
    
    - If an os entropy source is avaible then we declare the buffer
      content as additional data by setting randomness to zero and
      trigger a regular   reseeding.
    
    - If no os entropy source is available, a reseeding will fail
      inevitably. So drbg_add() uses a trick to mix the buffer contents
      into the DRBG state without forcing a reseeding: it generates a
      dummy random byte, using the buffer content as additional data.
    
    Related-to: #7449
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/7456)
    
    (cherry picked from commit 8817215d5c52a76f2b184b624bde4df8556dee6d)

commit 35a34508ef4d649ace4e373e1d019192b7e38c36
Author: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
Date:   Fri Oct 26 22:10:27 2018 +0200

    Backport some DRBG renamings and typo fixes
    
    In commit 8bf366519661 some renamings andd typo fixes were made
    while adding back the DRBG-HMAC and DRBG-HASH implementation.
    Since the commit could not be backported, a lot of unnecessary
    differences between master and 1.1.1 were introduced.
    
    These differences result in tiresome merge conflicts when
    cherry-picking. To minimize these merge-conflicts, this patch
    ports all 'non-feature' changes of commit 8bf366519661
    (e.g., renamings of private variables, fixes of typographical
    errors, comment changes) manually back to 1.1.1.
    
    The commits a83dc59afa2e (#7399) and 8817215d5c52 (#7456)
    failed to cherry-pick previously to 1.1.1, with this patch
    they both cherry-pick without conflicts.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    Reviewed-by: Bernd Edlinger <bernd.edlinger at hotmail.de>
    (Merged from https://github.com/openssl/openssl/pull/7505)

-----------------------------------------------------------------------

Summary of changes:
 crypto/rand/drbg_lib.c      | 123 +++++++++++++++++++++++++-------
 crypto/rand/rand_lcl.h      |  12 ++--
 crypto/rand/rand_lib.c      |   2 +
 crypto/rand/rand_unix.c     |   2 +-
 include/openssl/rand_drbg.h |   8 ++-
 test/drbgtest.c             | 166 ++++++++++++++++++++++++++++----------------
 6 files changed, 218 insertions(+), 95 deletions(-)

diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c
index f57d6a2..f396f83 100644
--- a/crypto/rand/drbg_lib.c
+++ b/crypto/rand/drbg_lib.c
@@ -316,6 +316,13 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg,
         max_entropylen += drbg->max_noncelen;
     }
 
+    drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
+    if (drbg->reseed_next_counter) {
+        drbg->reseed_next_counter++;
+        if(!drbg->reseed_next_counter)
+            drbg->reseed_next_counter = 1;
+    }
+
     if (drbg->get_entropy != NULL)
         entropylen = drbg->get_entropy(drbg, &entropy, min_entropy,
                                        min_entropylen, max_entropylen, 0);
@@ -341,14 +348,9 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg,
     }
 
     drbg->state = DRBG_READY;
-    drbg->generate_counter = 0;
+    drbg->reseed_gen_counter = 0;
     drbg->reseed_time = time(NULL);
-    if (drbg->reseed_counter > 0) {
-        if (drbg->parent == NULL)
-            drbg->reseed_counter++;
-        else
-            drbg->reseed_counter = drbg->parent->reseed_counter;
-    }
+    tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter);
 
  end:
     if (entropy != NULL && drbg->cleanup_entropy != NULL)
@@ -423,6 +425,14 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg,
     }
 
     drbg->state = DRBG_ERROR;
+
+    drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
+    if (drbg->reseed_next_counter) {
+        drbg->reseed_next_counter++;
+        if(!drbg->reseed_next_counter)
+            drbg->reseed_next_counter = 1;
+    }
+
     if (drbg->get_entropy != NULL)
         entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
                                        drbg->min_entropylen,
@@ -438,14 +448,9 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg,
         goto end;
 
     drbg->state = DRBG_READY;
-    drbg->generate_counter = 0;
+    drbg->reseed_gen_counter = 0;
     drbg->reseed_time = time(NULL);
-    if (drbg->reseed_counter > 0) {
-        if (drbg->parent == NULL)
-            drbg->reseed_counter++;
-        else
-            drbg->reseed_counter = drbg->parent->reseed_counter;
-    }
+    tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter);
 
  end:
     if (entropy != NULL && drbg->cleanup_entropy != NULL)
@@ -607,7 +612,7 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
     }
 
     if (drbg->reseed_interval > 0) {
-        if (drbg->generate_counter >= drbg->reseed_interval)
+        if (drbg->reseed_gen_counter >= drbg->reseed_interval)
             reseed_required = 1;
     }
     if (drbg->reseed_time_interval > 0) {
@@ -616,8 +621,11 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
             || 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)
+    if (drbg->parent != NULL) {
+        unsigned int reseed_counter = tsan_load(&drbg->reseed_prop_counter);
+        if (reseed_counter > 0
+                && tsan_load(&drbg->parent->reseed_prop_counter)
+                   != reseed_counter)
             reseed_required = 1;
     }
 
@@ -636,7 +644,7 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
         return 0;
     }
 
-    drbg->generate_counter++;
+    drbg->reseed_gen_counter++;
 
     return 1;
 }
@@ -689,7 +697,8 @@ int RAND_DRBG_set_callbacks(RAND_DRBG *drbg,
                             RAND_DRBG_get_nonce_fn get_nonce,
                             RAND_DRBG_cleanup_nonce_fn cleanup_nonce)
 {
-    if (drbg->state != DRBG_UNINITIALISED)
+    if (drbg->state != DRBG_UNINITIALISED
+            || drbg->parent != NULL)
         return 0;
     drbg->get_entropy = get_entropy;
     drbg->cleanup_entropy = cleanup_entropy;
@@ -866,7 +875,7 @@ static RAND_DRBG *drbg_setup(RAND_DRBG *parent)
         goto err;
 
     /* enable seed propagation */
-    drbg->reseed_counter = 1;
+    tsan_store(&drbg->reseed_prop_counter, 1);
 
     /*
      * Ignore instantiation error to support just-in-time instantiation.
@@ -955,11 +964,53 @@ static int drbg_bytes(unsigned char *out, int count)
     return ret;
 }
 
+/*
+ * Calculates the minimum length of a full entropy buffer
+ * which is necessary to seed (i.e. instantiate) the DRBG
+ * successfully.
+ *
+ * NOTE: There is a copy of this function in drbgtest.c.
+ *       If you change anything here, you need to update
+ *       the copy accordingly.
+ */
+static size_t rand_drbg_seedlen(RAND_DRBG *drbg)
+{
+    /*
+     * If no os entropy source is available then RAND_seed(buffer, bufsize)
+     * is expected to succeed if and only if the buffer length satisfies
+     * the following requirements, which follow from the calculations
+     * in RAND_DRBG_instantiate().
+     */
+    size_t min_entropy = drbg->strength;
+    size_t min_entropylen = drbg->min_entropylen;
+
+    /*
+     * Extra entropy for the random nonce in the absence of a
+     * get_nonce callback, see comment in RAND_DRBG_instantiate().
+     */
+    if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) {
+        min_entropy += drbg->strength / 2;
+        min_entropylen += drbg->min_noncelen;
+    }
+
+    /*
+     * Convert entropy requirement from bits to bytes
+     * (dividing by 8 without rounding upwards, because
+     * all entropy requirements are divisible by 8).
+     */
+    min_entropy >>= 3;
+
+    /* Return a value that satisfies both requirements */
+    return min_entropy > min_entropylen ? min_entropy : min_entropylen;
+}
+
 /* Implements the default OpenSSL RAND_add() method */
 static int drbg_add(const void *buf, int num, double randomness)
 {
     int ret = 0;
     RAND_DRBG *drbg = RAND_DRBG_get0_master();
+    size_t buflen;
+    size_t seedlen = rand_drbg_seedlen(drbg);
 
     if (drbg == NULL)
         return 0;
@@ -967,7 +1018,31 @@ static int drbg_add(const void *buf, int num, double randomness)
     if (num < 0 || randomness < 0.0)
         return 0;
 
-    if (randomness > (double)RAND_DRBG_STRENGTH) {
+    buflen = (size_t)num;
+
+    if (buflen < seedlen || randomness < (double) seedlen) {
+#if defined(OPENSSL_RAND_SEED_NONE)
+        /*
+         * If no os entropy source is available, a reseeding will fail
+         * inevitably. So we use a trick to mix the buffer contents into
+         * the DRBG state without forcing a reseeding: we generate a
+         * dummy random byte, using the buffer content as additional data.
+         */
+        unsigned char dummy[1];
+
+        return RAND_DRBG_generate(drbg, dummy, sizeof(dummy), 0, buf, buflen);
+#else
+        /*
+         * If an os entropy source is avaible then we declare the buffer content
+         * as additional data by setting randomness to zero and trigger a regular
+         * reseeding.
+         */
+        randomness = 0.0;
+#endif
+    }
+
+
+    if (randomness > (double)seedlen) {
         /*
          * The purpose of this check is to bound |randomness| by a
          * relatively small value in order to prevent an integer
@@ -976,13 +1051,11 @@ static int drbg_add(const void *buf, int num, double randomness)
          * not bits, so this value corresponds to eight times the
          * security strength.
          */
-        randomness = (double)RAND_DRBG_STRENGTH;
+        randomness = (double)seedlen;
     }
 
     rand_drbg_lock(drbg);
-    ret = rand_drbg_restart(drbg, buf,
-                            (size_t)(unsigned int)num,
-                            (size_t)(8*randomness));
+    ret = rand_drbg_restart(drbg, buf, buflen, (size_t)(8 * randomness));
     rand_drbg_unlock(drbg);
 
     return ret;
diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h
index 38614a8..10323a0 100644
--- a/crypto/rand/rand_lcl.h
+++ b/crypto/rand/rand_lcl.h
@@ -16,6 +16,7 @@
 # include <openssl/hmac.h>
 # include <openssl/ec.h>
 # include <openssl/rand_drbg.h>
+# include "internal/tsan_assist.h"
 
 # include "internal/numbers.h"
 
@@ -80,7 +81,7 @@ typedef enum drbg_status_e {
 } DRBG_STATUS;
 
 
-/* intantiate */
+/* instantiate */
 typedef int (*RAND_DRBG_instantiate_fn)(RAND_DRBG *ctx,
                                         const unsigned char *ent,
                                         size_t entlen,
@@ -94,7 +95,7 @@ typedef int (*RAND_DRBG_reseed_fn)(RAND_DRBG *ctx,
                                    size_t entlen,
                                    const unsigned char *adin,
                                    size_t adinlen);
-/* generat output */
+/* generate output */
 typedef int (*RAND_DRBG_generate_fn)(RAND_DRBG *ctx,
                                      unsigned char *out,
                                      size_t outlen,
@@ -167,7 +168,7 @@ struct rand_drbg_st {
     int type; /* the nid of the underlying algorithm */
     /*
      * Stores the value of the rand_fork_count global as of when we last
-     * reseeded.  The DRG reseeds automatically whenever drbg->fork_count !=
+     * reseeded.  The DRBG reseeds automatically whenever drbg->fork_count !=
      * rand_fork_count.  Used to provide fork-safety and reseed this DRBG in
      * the child process.
      */
@@ -208,7 +209,7 @@ struct rand_drbg_st {
     size_t max_perslen, max_adinlen;
 
     /* Counts the number of generate requests since the last reseed. */
-    unsigned int generate_counter;
+    unsigned int reseed_gen_counter;
     /*
      * Maximum number of generate requests until a reseed is required.
      * This value is ignored if it is zero.
@@ -231,7 +232,8 @@ struct rand_drbg_st {
      * is added by RAND_add() or RAND_seed() will have an immediate effect on
      * the output of RAND_bytes() resp. RAND_priv_bytes().
      */
-    unsigned int reseed_counter;
+    TSAN_QUALIFIER unsigned int reseed_prop_counter;
+    unsigned int reseed_next_counter;
 
     size_t seedlen;
     DRBG_STATUS state;
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index 29d93a8..440c19c 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -174,6 +174,8 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg,
                                    prediction_resistance,
                                    NULL, 0) != 0)
                 bytes = bytes_needed;
+            drbg->reseed_next_counter
+                = tsan_load(&drbg->parent->reseed_prop_counter);
             rand_drbg_unlock(drbg->parent);
 
             rand_pool_add_end(pool, bytes, 8 * bytes);
diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c
index a46823b..cb3a6b2 100644
--- a/crypto/rand/rand_unix.c
+++ b/crypto/rand/rand_unix.c
@@ -584,7 +584,7 @@ int rand_pool_add_nonce_data(RAND_POOL *pool)
 
     /*
      * Add process id, thread id, and a high resolution timestamp to
-     * ensure that the nonce is unique whith high probability for
+     * ensure that the nonce is unique with high probability for
      * different process instances.
      */
     data.pid = getpid();
diff --git a/include/openssl/rand_drbg.h b/include/openssl/rand_drbg.h
index cfc7fb7..a7dd0b5 100644
--- a/include/openssl/rand_drbg.h
+++ b/include/openssl/rand_drbg.h
@@ -33,9 +33,9 @@
  * Default security strength (in the sense of [NIST SP 800-90Ar1])
  *
  * NIST SP 800-90Ar1 supports the strength of the DRBG being smaller than that
- * of the cipher by collecting less entropy. The current DRBG implemantion does
- * not take RAND_DRBG_STRENGTH into account and sets the strength of the DRBG
- * to that of the cipher.
+ * of the cipher by collecting less entropy. The current DRBG implementation
+ * does not take RAND_DRBG_STRENGTH into account and sets the strength of the
+ * DRBG to that of the cipher.
  *
  * RAND_DRBG_STRENGTH is currently only used for the legacy RAND
  * implementation.
@@ -44,7 +44,9 @@
  * NID_aes_256_ctr
  */
 # define RAND_DRBG_STRENGTH             256
+/* Default drbg type */
 # define RAND_DRBG_TYPE                 NID_aes_256_ctr
+/* Default drbg flags */
 # define RAND_DRBG_FLAGS                0
 
 
diff --git a/test/drbgtest.c b/test/drbgtest.c
index 4e0d80f..b4453b0 100644
--- a/test/drbgtest.c
+++ b/test/drbgtest.c
@@ -283,7 +283,7 @@ static int error_check(DRBG_SELFTEST_DATA *td)
     RAND_DRBG *drbg = NULL;
     TEST_CTX t;
     unsigned char buff[1024];
-    unsigned int generate_counter_tmp;
+    unsigned int reseed_counter_tmp;
     int ret = 0;
 
     if (!TEST_ptr(drbg = RAND_DRBG_new(0, 0, NULL)))
@@ -302,7 +302,7 @@ static int error_check(DRBG_SELFTEST_DATA *td)
      * Entropy source tests
      */
 
-    /* Test entropy source failure detecion: i.e. returns no data */
+    /* Test entropy source failure detection: i.e. returns no data */
     t.entropylen = 0;
     if (TEST_int_le(RAND_DRBG_instantiate(drbg, td->pers, td->perslen), 0))
         goto err;
@@ -378,15 +378,15 @@ static int error_check(DRBG_SELFTEST_DATA *td)
     /* Instantiate again with valid data */
     if (!instantiate(drbg, td, &t))
         goto err;
-    generate_counter_tmp = drbg->generate_counter;
-    drbg->generate_counter = drbg->reseed_interval;
+    reseed_counter_tmp = drbg->reseed_gen_counter;
+    drbg->reseed_gen_counter = drbg->reseed_interval;
 
     /* Generate output and check entropy has been requested for reseed */
     t.entropycnt = 0;
     if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0,
                                       td->adin, td->adinlen))
             || !TEST_int_eq(t.entropycnt, 1)
-            || !TEST_int_eq(drbg->generate_counter, generate_counter_tmp + 1)
+            || !TEST_int_eq(drbg->reseed_gen_counter, reseed_counter_tmp + 1)
             || !uninstantiate(drbg))
         goto err;
 
@@ -403,15 +403,15 @@ static int error_check(DRBG_SELFTEST_DATA *td)
     /* Test reseed counter works */
     if (!instantiate(drbg, td, &t))
         goto err;
-    generate_counter_tmp = drbg->generate_counter;
-    drbg->generate_counter = drbg->reseed_interval;
+    reseed_counter_tmp = drbg->reseed_gen_counter;
+    drbg->reseed_gen_counter = drbg->reseed_interval;
 
     /* Generate output and check entropy has been requested for reseed */
     t.entropycnt = 0;
     if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0,
                                       td->adin, td->adinlen))
             || !TEST_int_eq(t.entropycnt, 1)
-            || !TEST_int_eq(drbg->generate_counter, generate_counter_tmp + 1)
+            || !TEST_int_eq(drbg->reseed_gen_counter, reseed_counter_tmp + 1)
             || !uninstantiate(drbg))
         goto err;
 
@@ -591,14 +591,14 @@ static int test_drbg_reseed(int expect_success,
      */
 
     /* Test whether seed propagation is enabled */
-    if (!TEST_int_ne(master->reseed_counter, 0)
-        || !TEST_int_ne(public->reseed_counter, 0)
-        || !TEST_int_ne(private->reseed_counter, 0))
+    if (!TEST_int_ne(master->reseed_prop_counter, 0)
+        || !TEST_int_ne(public->reseed_prop_counter, 0)
+        || !TEST_int_ne(private->reseed_prop_counter, 0))
         return 0;
 
     /* Check whether the master DRBG's reseed counter is the largest one */
-    if (!TEST_int_le(public->reseed_counter, master->reseed_counter)
-        || !TEST_int_le(private->reseed_counter, master->reseed_counter))
+    if (!TEST_int_le(public->reseed_prop_counter, master->reseed_prop_counter)
+        || !TEST_int_le(private->reseed_prop_counter, master->reseed_prop_counter))
         return 0;
 
     /*
@@ -643,8 +643,8 @@ static int test_drbg_reseed(int expect_success,
 
     if (expect_success == 1) {
         /* Test whether all three reseed counters are synchronized */
-        if (!TEST_int_eq(public->reseed_counter, master->reseed_counter)
-            || !TEST_int_eq(private->reseed_counter, master->reseed_counter))
+        if (!TEST_int_eq(public->reseed_prop_counter, master->reseed_prop_counter)
+            || !TEST_int_eq(private->reseed_prop_counter, master->reseed_prop_counter))
             return 0;
 
         /* Test whether reseed time of master DRBG is set correctly */
@@ -668,7 +668,7 @@ static int test_drbg_reseed(int expect_success,
  * setup correctly, in particular whether reseeding  works
  * as designed.
  */
-static int test_rand_reseed(void)
+static int test_rand_drbg_reseed(void)
 {
     RAND_DRBG *master, *public, *private;
     unsigned char rand_add_buf[256];
@@ -723,7 +723,7 @@ static int test_rand_reseed(void)
      * Test whether the public and private DRBG are both reseeded when their
      * reseed counters differ from the master's reseed counter.
      */
-    master->reseed_counter++;
+    master->reseed_prop_counter++;
     if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 1, 1)))
         goto error;
     reset_drbg_hook_ctx();
@@ -732,8 +732,8 @@ static int test_rand_reseed(void)
      * Test whether the public DRBG is reseeded when its reseed counter differs
      * from the master's reseed counter.
      */
-    master->reseed_counter++;
-    private->reseed_counter++;
+    master->reseed_prop_counter++;
+    private->reseed_prop_counter++;
     if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 1, 0)))
         goto error;
     reset_drbg_hook_ctx();
@@ -742,8 +742,8 @@ static int test_rand_reseed(void)
      * Test whether the private DRBG is reseeded when its reseed counter differs
      * from the master's reseed counter.
      */
-    master->reseed_counter++;
-    public->reseed_counter++;
+    master->reseed_prop_counter++;
+    public->reseed_prop_counter++;
     if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 0, 1)))
         goto error;
     reset_drbg_hook_ctx();
@@ -765,7 +765,7 @@ static int test_rand_reseed(void)
      * Test whether none of the DRBGs is reseed if the master fails to reseed
      */
     master_ctx.fail = 1;
-    master->reseed_counter++;
+    master->reseed_prop_counter++;
     RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf));
     if (!TEST_true(test_drbg_reseed(0, master, public, private, 0, 0, 0)))
         goto error;
@@ -875,64 +875,107 @@ static int test_multi_thread(void)
 }
 #endif
 
+#ifdef OPENSSL_RAND_SEED_NONE
 /*
- * This function only returns the entropy already added with RAND_add(),
- * and does not get entropy from the OS.
+ * Calculates the minimum buffer length which needs to be
+ * provided to RAND_seed() in order to successfully
+ * instantiate the DRBG.
  *
- * Returns 0 on failure and the size of the buffer on success.
+ * Copied from rand_drbg_seedlen() in rand_drbg.c
  */
-static size_t get_pool_entropy(RAND_DRBG *drbg,
-                               unsigned char **pout,
-                               int entropy, size_t min_len, size_t max_len,
-                               int prediction_resistance)
+static size_t rand_drbg_seedlen(RAND_DRBG *drbg)
 {
-    if (drbg->pool == NULL)
-        return 0;
+    /*
+     * If no os entropy source is available then RAND_seed(buffer, bufsize)
+     * is expected to succeed if and only if the buffer length satisfies
+     * the following requirements, which follow from the calculations
+     * in RAND_DRBG_instantiate().
+     */
+    size_t min_entropy = drbg->strength;
+    size_t min_entropylen = drbg->min_entropylen;
 
-    if (drbg->pool->entropy < (size_t)entropy || drbg->pool->len < min_len
-        || drbg->pool->len > max_len)
-        return 0;
+    /*
+     * Extra entropy for the random nonce in the absence of a
+     * get_nonce callback, see comment in RAND_DRBG_instantiate().
+     */
+    if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) {
+        min_entropy += drbg->strength / 2;
+        min_entropylen += drbg->min_noncelen;
+    }
+
+    /*
+     * Convert entropy requirement from bits to bytes
+     * (dividing by 8 without rounding upwards, because
+     * all entropy requirements are divisible by 8).
+     */
+    min_entropy >>= 3;
 
-    *pout = drbg->pool->buffer;
-    return drbg->pool->len;
+    /* Return a value that satisfies both requirements */
+    return min_entropy > min_entropylen ? min_entropy : min_entropylen;
 }
+#endif /*OPENSSL_RAND_SEED_NONE*/
 
 /*
- * Clean up the entropy that get_pool_entropy() returned.
+ * Test that instantiation with RAND_seed() works as expected
+ *
+ * If no os entropy source is available then RAND_seed(buffer, bufsize)
+ * is expected to succeed if and only if the buffer length is at least
+ * rand_drbg_seedlen(master) bytes.
+ *
+ * If an os entropy source is available then RAND_seed(buffer, bufsize)
+ * is expected to succeed always.
  */
-static void cleanup_pool_entropy(RAND_DRBG *drbg, unsigned char *out, size_t outlen)
+static int test_rand_seed(void)
 {
-    OPENSSL_free(drbg->pool);
-    drbg->pool = NULL;
+    RAND_DRBG *master = RAND_DRBG_get0_master();
+    unsigned char rand_buf[256];
+    size_t rand_buflen;
+#ifdef OPENSSL_RAND_SEED_NONE
+    size_t required_seed_buflen = rand_drbg_seedlen(master);
+#else
+    size_t required_seed_buflen = 0;
+#endif
+
+    memset(rand_buf, 0xCD, sizeof(rand_buf));
+
+    for ( rand_buflen = 256 ; rand_buflen > 0 ; --rand_buflen ) {
+        RAND_DRBG_uninstantiate(master);
+        RAND_seed(rand_buf, rand_buflen);
+
+        if (!TEST_int_eq(RAND_status(),
+                         (rand_buflen >= required_seed_buflen)))
+            return 0;
+    }
+
+    return 1;
 }
 
 /*
- * Test that instantiating works when OS entropy is not available and that
- * RAND_add() is enough to reseed it.
+ * Test that adding additional data with RAND_add() works as expected
+ * when the master DRBG is instantiated (and below its reseed limit).
+ *
+ * This should succeed regardless of whether an os entropy source is
+ * available or not.
  */
 static int test_rand_add(void)
 {
-    RAND_DRBG *master = RAND_DRBG_get0_master();
-    RAND_DRBG_get_entropy_fn old_get_entropy = master->get_entropy;
-    RAND_DRBG_cleanup_entropy_fn old_cleanup_entropy = master->cleanup_entropy;
-    int rv = 0;
-    unsigned char rand_add_buf[256];
+    unsigned char rand_buf[256];
+    size_t rand_buflen;
 
-    master->get_entropy = get_pool_entropy;
-    master->cleanup_entropy = cleanup_pool_entropy;
-    master->reseed_counter++;
-    RAND_DRBG_uninstantiate(master);
-    memset(rand_add_buf, 0xCD, sizeof(rand_add_buf));
-    RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf));
-    if (!TEST_true(RAND_DRBG_instantiate(master, NULL, 0)))
-        goto error;
+    memset(rand_buf, 0xCD, sizeof(rand_buf));
 
-    rv = 1;
+    /* make sure it's instantiated */
+    RAND_seed(rand_buf, sizeof(rand_buf));
+    if (!TEST_true(RAND_status()))
+        return 0;
 
-error:
-    master->get_entropy = old_get_entropy;
-    master->cleanup_entropy = old_cleanup_entropy;
-    return rv;
+    for ( rand_buflen = 256 ; rand_buflen > 0 ; --rand_buflen ) {
+        RAND_add(rand_buf, rand_buflen, 0.0);
+        if (!TEST_true(RAND_status()))
+            return 0;
+    }
+
+    return 1;
 }
 
 int setup_tests(void)
@@ -941,7 +984,8 @@ int setup_tests(void)
 
     ADD_ALL_TESTS(test_kats, OSSL_NELEM(drbg_test));
     ADD_ALL_TESTS(test_error_checks, OSSL_NELEM(drbg_test));
-    ADD_TEST(test_rand_reseed);
+    ADD_TEST(test_rand_drbg_reseed);
+    ADD_TEST(test_rand_seed);
     ADD_TEST(test_rand_add);
 #if defined(OPENSSL_THREADS)
     ADD_TEST(test_multi_thread);


More information about the openssl-commits mailing list