Make rand_pool buffers more dynamic in their sizing.
authorPauli <paul.dale@oracle.com>
Tue, 23 Jul 2019 08:07:19 +0000 (18:07 +1000)
committerPauli <paul.dale@oracle.com>
Tue, 23 Jul 2019 13:30:12 +0000 (23:30 +1000)
The rand pool support allocates maximal sized buffers -- this is typically
12288 bytes in size.  These pools are allocated in secure memory which is a
scarse resource.  They are also allocated per DRBG of which there are up to two
per thread.

This change allocates 64 byte pools and grows them dynamically if required.
64 is chosen to be sufficiently large so that pools do not normally need to
grow.

Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
(Merged from https://github.com/openssl/openssl/pull/9428)

(cherry picked from commit a6a66e4511eec0f4ecc2943117a42b3723eb2222)

CHANGES
crypto/err/openssl.txt
crypto/rand/rand_err.c
crypto/rand/rand_lcl.h
crypto/rand/rand_lib.c
include/openssl/randerr.h

diff --git a/CHANGES b/CHANGES
index 47ea8e09785fb62b05e06553163bcfe3fd3f6f30..de9c7c1f4b30086d93c1ddc223ad3fd452b11785 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -15,6 +15,9 @@
      private key for those. This avoids leaking bit 0 of the private key.
      [Bernd Edlinger]
 
+  *) Significantly reduce secure memory usage by the randomness pools.
+     [Paul Dale]
+
   *) Revert the DEVRANDOM_WAIT feature for Linux systems
 
      The DEVRANDOM_WAIT feature added a select() call to wait for the
index 907eeaa8c3ec51426c213663a888c787f11d63e3..722a08773ad63ba0582ce697e1332056ecee36c6 100644 (file)
@@ -1025,6 +1025,7 @@ RAND_F_RAND_POOL_ADD_BEGIN:113:rand_pool_add_begin
 RAND_F_RAND_POOL_ADD_END:114:rand_pool_add_end
 RAND_F_RAND_POOL_ATTACH:124:rand_pool_attach
 RAND_F_RAND_POOL_BYTES_NEEDED:115:rand_pool_bytes_needed
+RAND_F_RAND_POOL_GROW:125:rand_pool_grow
 RAND_F_RAND_POOL_NEW:116:rand_pool_new
 RAND_F_RAND_WRITE_FILE:112:RAND_write_file
 RSA_F_CHECK_PADDING_MD:140:check_padding_md
index 6a870455d50a8ac0b1a7cf33668e923ef4a624cc..ae4d8559fb2850562cedf66d3636456e1e099e73 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -47,6 +47,7 @@ static const ERR_STRING_DATA RAND_str_functs[] = {
     {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ATTACH, 0), "rand_pool_attach"},
     {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_BYTES_NEEDED, 0),
      "rand_pool_bytes_needed"},
+    {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_GROW, 0), "rand_pool_grow"},
     {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_NEW, 0), "rand_pool_new"},
     {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_WRITE_FILE, 0), "RAND_write_file"},
     {0, NULL}
index a48e08a92372708f58a093a57cc92c4afc0b9606..148da8460d8f44fcd6a9167ed8a0da26732d7ecc 100644 (file)
  *                                1.5 * (RAND_DRBG_STRENGTH / 8))
  */
 
+/*
+ * Initial allocation minimum.
+ *
+ * There is a distinction between the secure and normal allocation minimums.
+ * Ideally, the secure allocation size should be a power of two.  The normal
+ * allocation size doesn't have any such restriction.
+ *
+ * The secure value is based on 128 bits of secure material, which is 16 bytes.
+ * Typically, the DRBGs will set a minimum larger than this so optimal
+ * allocation ought to take place (for full quality seed material).
+ *
+ * The normal value has been chosed by noticing that the rand_drbg_get_nonce
+ * function is usually the largest of the built in allocation (twenty four
+ * bytes and then appending another sixteen bytes).  This means the buffer ends
+ * with 40 bytes.  The value of forty eight is comfortably above this which
+ * allows some slack in the platform specific values used.
+ */
+# define RAND_POOL_MIN_ALLOCATION(secure) ((secure) ? 16 : 48)
 
 /* DRBG status values */
 typedef enum drbg_status_e {
@@ -154,6 +172,7 @@ struct rand_pool_st {
 
     size_t min_len; /* minimum number of random bytes requested */
     size_t max_len; /* maximum number of random bytes (allocated buffer size) */
+    size_t alloc_len; /* current number of bytes allocated */
     size_t entropy; /* current entropy count in bits */
     size_t entropy_requested; /* requested entropy count in bits */
 };
index f658634edd50050c531d2129b738a773509abe30..48da2b9539b5fbe0442c9a03c92cf4f61f23f731 100644 (file)
@@ -437,6 +437,7 @@ RAND_POOL *rand_pool_new(int entropy_requested, int secure,
                          size_t min_len, size_t max_len)
 {
     RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool));
+    size_t min_alloc_size = RAND_POOL_MIN_ALLOCATION(secure);
 
     if (pool == NULL) {
         RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE);
@@ -446,11 +447,14 @@ RAND_POOL *rand_pool_new(int entropy_requested, int secure,
     pool->min_len = min_len;
     pool->max_len = (max_len > RAND_POOL_MAX_LENGTH) ?
         RAND_POOL_MAX_LENGTH : max_len;
+    pool->alloc_len = min_len < min_alloc_size ? min_alloc_size : min_len;
+    if (pool->alloc_len > pool->max_len)
+        pool->alloc_len = pool->max_len;
 
     if (secure)
-        pool->buffer = OPENSSL_secure_zalloc(pool->max_len);
+        pool->buffer = OPENSSL_secure_zalloc(pool->alloc_len);
     else
-        pool->buffer = OPENSSL_zalloc(pool->max_len);
+        pool->buffer = OPENSSL_zalloc(pool->alloc_len);
 
     if (pool->buffer == NULL) {
         RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE);
@@ -493,7 +497,7 @@ RAND_POOL *rand_pool_attach(const unsigned char *buffer, size_t len,
 
     pool->attached = 1;
 
-    pool->min_len = pool->max_len = pool->len;
+    pool->min_len = pool->max_len = pool->alloc_len = pool->len;
     pool->entropy = entropy;
 
     return pool;
@@ -515,9 +519,9 @@ void rand_pool_free(RAND_POOL *pool)
      */
     if (!pool->attached) {
         if (pool->secure)
-            OPENSSL_secure_clear_free(pool->buffer, pool->max_len);
+            OPENSSL_secure_clear_free(pool->buffer, pool->alloc_len);
         else
-            OPENSSL_clear_free(pool->buffer, pool->max_len);
+            OPENSSL_clear_free(pool->buffer, pool->alloc_len);
     }
 
     OPENSSL_free(pool);
@@ -650,6 +654,36 @@ size_t rand_pool_bytes_remaining(RAND_POOL *pool)
     return pool->max_len - pool->len;
 }
 
+static int rand_pool_grow(RAND_POOL *pool, size_t len)
+{
+    if (len > pool->alloc_len - pool->len) {
+        unsigned char *p;
+        const size_t limit = pool->max_len / 2;
+        size_t newlen = pool->alloc_len;
+
+        do
+            newlen = newlen < limit ? newlen * 2 : pool->max_len;
+        while (len > newlen - pool->len);
+
+        if (pool->secure)
+            p = OPENSSL_secure_zalloc(newlen);
+        else
+            p = OPENSSL_zalloc(newlen);
+        if (p == NULL) {
+            RANDerr(RAND_F_RAND_POOL_GROW, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        memcpy(p, pool->buffer, pool->len);
+        if (pool->secure)
+            OPENSSL_secure_clear_free(pool->buffer, pool->alloc_len);
+        else
+            OPENSSL_clear_free(pool->buffer, pool->alloc_len);
+        pool->buffer = p;
+        pool->alloc_len = newlen;
+    }
+    return 1;
+}
+
 /*
  * Add random bytes to the random pool.
  *
@@ -673,6 +707,8 @@ int rand_pool_add(RAND_POOL *pool,
     }
 
     if (len > 0) {
+        if (!rand_pool_grow(pool, len))
+            return 0;
         memcpy(pool->buffer + pool->len, buffer, len);
         pool->len += len;
         pool->entropy += entropy;
@@ -708,6 +744,8 @@ unsigned char *rand_pool_add_begin(RAND_POOL *pool, size_t len)
         return NULL;
     }
 
+    if (!rand_pool_grow(pool, len))
+        return NULL;
     return pool->buffer + pool->len;
 }
 
index d9aa9b3d7061cee15db23b9d04efc077196c28a3..70d1a17a4c6bdb99beb61e0494041c726c04564c 100644 (file)
@@ -11,9 +11,7 @@
 #ifndef HEADER_RANDERR_H
 # define HEADER_RANDERR_H
 
-# ifndef HEADER_SYMHACKS_H
-#  include <openssl/symhacks.h>
-# endif
+# include <openssl/symhacks.h>
 
 # ifdef  __cplusplus
 extern "C"
@@ -46,6 +44,7 @@ int ERR_load_RAND_strings(void);
 # define RAND_F_RAND_POOL_ADD_END                         114
 # define RAND_F_RAND_POOL_ATTACH                          124
 # define RAND_F_RAND_POOL_BYTES_NEEDED                    115
+# define RAND_F_RAND_POOL_GROW                            125
 # define RAND_F_RAND_POOL_NEW                             116
 # define RAND_F_RAND_WRITE_FILE                           112