From: Pauli Date: Tue, 23 Jul 2019 08:07:19 +0000 (+1000) Subject: Make rand_pool buffers more dynamic in their sizing. X-Git-Tag: OpenSSL_1_1_1d~89 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=b4b42d441d350b48449ea93aaa035152123f70ae;p=oweals%2Fopenssl.git Make rand_pool buffers more dynamic in their sizing. 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 (Merged from https://github.com/openssl/openssl/pull/9428) (cherry picked from commit a6a66e4511eec0f4ecc2943117a42b3723eb2222) --- diff --git a/CHANGES b/CHANGES index 47ea8e0978..de9c7c1f4b 100644 --- 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 diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 907eeaa8c3..722a08773a 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -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 diff --git a/crypto/rand/rand_err.c b/crypto/rand/rand_err.c index 6a870455d5..ae4d8559fb 100644 --- a/crypto/rand/rand_err.c +++ b/crypto/rand/rand_err.c @@ -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} diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h index a48e08a923..148da8460d 100644 --- a/crypto/rand/rand_lcl.h +++ b/crypto/rand/rand_lcl.h @@ -72,6 +72,24 @@ * 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 */ }; diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index f658634edd..48da2b9539 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -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; } diff --git a/include/openssl/randerr.h b/include/openssl/randerr.h index d9aa9b3d70..70d1a17a4c 100644 --- a/include/openssl/randerr.h +++ b/include/openssl/randerr.h @@ -11,9 +11,7 @@ #ifndef HEADER_RANDERR_H # define HEADER_RANDERR_H -# ifndef HEADER_SYMHACKS_H -# include -# endif +# include # 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