diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/err/openssl.txt | 1 | ||||
-rw-r--r-- | crypto/include/internal/rand_int.h | 2 | ||||
-rw-r--r-- | crypto/rand/drbg_ctr.c | 4 | ||||
-rw-r--r-- | crypto/rand/drbg_hash.c | 4 | ||||
-rw-r--r-- | crypto/rand/drbg_hmac.c | 4 | ||||
-rw-r--r-- | crypto/rand/drbg_lib.c | 17 | ||||
-rw-r--r-- | crypto/rand/rand_err.c | 1 | ||||
-rw-r--r-- | crypto/rand/rand_lcl.h | 46 | ||||
-rw-r--r-- | crypto/rand/rand_lib.c | 79 | ||||
-rw-r--r-- | crypto/rand/rand_unix.c | 2 |
10 files changed, 116 insertions, 44 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 84e639305b..489ccc0986 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1016,6 +1016,7 @@ RAND_F_RAND_POOL_ACQUIRE_ENTROPY:122:rand_pool_acquire_entropy RAND_F_RAND_POOL_ADD:103:rand_pool_add 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_NEW:116:rand_pool_new RAND_F_RAND_WRITE_FILE:112:RAND_write_file diff --git a/crypto/include/internal/rand_int.h b/crypto/include/internal/rand_int.h index d91ee4c934..3c966ab96e 100644 --- a/crypto/include/internal/rand_int.h +++ b/crypto/include/internal/rand_int.h @@ -53,6 +53,8 @@ void rand_drbg_cleanup_additional_data(unsigned char *out, size_t outlen); * RAND_POOL functions */ RAND_POOL *rand_pool_new(int entropy_requested, size_t min_len, size_t max_len); +RAND_POOL *rand_pool_attach(const unsigned char *buffer, size_t len, + size_t entropy); void rand_pool_free(RAND_POOL *pool); const unsigned char *rand_pool_buffer(RAND_POOL *pool); diff --git a/crypto/rand/drbg_ctr.c b/crypto/rand/drbg_ctr.c index 0548237e7d..894c77d6eb 100644 --- a/crypto/rand/drbg_ctr.c +++ b/crypto/rand/drbg_ctr.c @@ -416,9 +416,9 @@ int drbg_ctr_init(RAND_DRBG *drbg) return 0; drbg->min_entropylen = ctr->keylen; - drbg->max_entropylen = DRBG_MINMAX_FACTOR * drbg->min_entropylen; + drbg->max_entropylen = DRBG_MAX_LENGTH; drbg->min_noncelen = drbg->min_entropylen / 2; - drbg->max_noncelen = DRBG_MINMAX_FACTOR * drbg->min_noncelen; + drbg->max_noncelen = DRBG_MAX_LENGTH; drbg->max_perslen = DRBG_MAX_LENGTH; drbg->max_adinlen = DRBG_MAX_LENGTH; } else { diff --git a/crypto/rand/drbg_hash.c b/crypto/rand/drbg_hash.c index 9caf5b27be..cae567beb4 100644 --- a/crypto/rand/drbg_hash.c +++ b/crypto/rand/drbg_hash.c @@ -332,10 +332,10 @@ int drbg_hash_init(RAND_DRBG *drbg) drbg->seedlen = HASH_PRNG_SMALL_SEEDLEN; drbg->min_entropylen = drbg->strength / 8; - drbg->max_entropylen = DRBG_MINMAX_FACTOR * drbg->min_entropylen; + drbg->max_entropylen = DRBG_MAX_LENGTH; drbg->min_noncelen = drbg->min_entropylen / 2; - drbg->max_noncelen = DRBG_MINMAX_FACTOR * drbg->min_noncelen; + drbg->max_noncelen = DRBG_MAX_LENGTH; drbg->max_perslen = DRBG_MAX_LENGTH; drbg->max_adinlen = DRBG_MAX_LENGTH; diff --git a/crypto/rand/drbg_hmac.c b/crypto/rand/drbg_hmac.c index 25c5b0301c..424c88cb26 100644 --- a/crypto/rand/drbg_hmac.c +++ b/crypto/rand/drbg_hmac.c @@ -223,10 +223,10 @@ int drbg_hmac_init(RAND_DRBG *drbg) drbg->seedlen = hmac->blocklen; drbg->min_entropylen = drbg->strength / 8; - drbg->max_entropylen = DRBG_MINMAX_FACTOR * drbg->min_entropylen; + drbg->max_entropylen = DRBG_MAX_LENGTH; drbg->min_noncelen = drbg->min_entropylen / 2; - drbg->max_noncelen = DRBG_MINMAX_FACTOR * drbg->min_noncelen; + drbg->max_noncelen = DRBG_MAX_LENGTH; drbg->max_perslen = DRBG_MAX_LENGTH; drbg->max_adinlen = DRBG_MAX_LENGTH; diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c index c59f3f0026..36b20c9398 100644 --- a/crypto/rand/drbg_lib.c +++ b/crypto/rand/drbg_lib.c @@ -556,8 +556,10 @@ int rand_drbg_restart(RAND_DRBG *drbg, if (drbg->pool != NULL) { RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); + drbg->state = DRBG_ERROR; rand_pool_free(drbg->pool); drbg->pool = NULL; + return 0; } if (buffer != NULL) { @@ -565,24 +567,25 @@ int rand_drbg_restart(RAND_DRBG *drbg, if (drbg->max_entropylen < len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_INPUT_TOO_LONG); + drbg->state = DRBG_ERROR; return 0; } if (entropy > 8 * len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE); + drbg->state = DRBG_ERROR; return 0; } /* will be picked up by the rand_drbg_get_entropy() callback */ - drbg->pool = rand_pool_new(entropy, len, len); + drbg->pool = rand_pool_attach(buffer, len, entropy); if (drbg->pool == NULL) return 0; - - rand_pool_add(drbg->pool, buffer, len, entropy); } else { if (drbg->max_adinlen < len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ADDITIONAL_INPUT_TOO_LONG); + drbg->state = DRBG_ERROR; return 0; } adin = buffer; @@ -1040,14 +1043,16 @@ static int drbg_add(const void *buf, int num, double randomness) if (num < 0 || randomness < 0.0) return 0; - if (randomness > (double)drbg->max_entropylen) { + if (randomness > (double)RAND_DRBG_STRENGTH) { /* * The purpose of this check is to bound |randomness| by a * relatively small value in order to prevent an integer * overflow when multiplying by 8 in the rand_drbg_restart() - * call below. + * call below. Note that randomness is measured in bytes, + * not bits, so this value corresponds to eight times the + * security strength. */ - return 0; + randomness = (double)RAND_DRBG_STRENGTH; } rand_drbg_lock(drbg); diff --git a/crypto/rand/rand_err.c b/crypto/rand/rand_err.c index 31480a6828..6a870455d5 100644 --- a/crypto/rand/rand_err.c +++ b/crypto/rand/rand_err.c @@ -44,6 +44,7 @@ static const ERR_STRING_DATA RAND_str_functs[] = { {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD_BEGIN, 0), "rand_pool_add_begin"}, {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD_END, 0), "rand_pool_add_end"}, + {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_NEW, 0), "rand_pool_new"}, diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h index 7b1c74d4b3..13f8cc8239 100644 --- a/crypto/rand/rand_lcl.h +++ b/crypto/rand/rand_lcl.h @@ -32,18 +32,42 @@ -/* Max size of additional input and personalization string. */ -# define DRBG_MAX_LENGTH 4096 +/* + * Maximum input size for the DRBG (entropy, nonce, personalization string) + * + * NIST SP800 90Ar1 allows a maximum of (1 << 35) bits i.e., (1 << 32) bytes. + * + * We lower it to 'only' INT32_MAX bytes, which is equivalent to 2 gigabytes. + */ +# define DRBG_MAX_LENGTH INT32_MAX + + /* - * The quotient between max_{entropy,nonce}len and min_{entropy,nonce}len + * Maximum allocation size for RANDOM_POOL buffers * - * The current factor is large enough that the RAND_POOL can store a - * random input which has a lousy entropy rate of 0.0625 bits per byte. - * This input will be sent through the derivation function which 'compresses' - * the low quality input into a high quality output. + * The max_len value for the buffer provided to the rand_drbg_get_entropy() + * callback is currently 2^31 bytes (2 gigabytes), if a derivation function + * is used. Since this is much too large to be allocated, the rand_pool_new() + * function chooses more modest values as default pool length, bounded + * by RAND_POOL_MIN_LENGTH and RAND_POOL_MAX_LENGTH + * + * The choice of the RAND_POOL_FACTOR is large enough such that the + * RAND_POOL can store a random input which has a lousy entropy rate of + * 8/256 (= 0.03125) bits per byte. This input will be sent through the + * derivation function which 'compresses' the low quality input into a + * high quality output. + * + * The factor 1.5 below is the pessimistic estimate for the extra amount + * of entropy required when no get_nonce() callback is defined. + */ +# define RAND_POOL_FACTOR 256 +# define RAND_POOL_MAX_LENGTH (RAND_POOL_FACTOR * \ + 3 * (RAND_DRBG_STRENGTH / 16)) +/* + * = (RAND_POOL_FACTOR * \ + * 1.5 * (RAND_DRBG_STRENGTH / 8)) */ -# define DRBG_MINMAX_FACTOR 128 /* DRBG status values */ @@ -142,10 +166,12 @@ struct rand_pool_st { unsigned char *buffer; /* points to the beginning of the random pool */ size_t len; /* current number of random bytes contained in the pool */ + int attached; /* true pool was attached to existing buffer */ + size_t min_len; /* minimum number of random bytes requested */ size_t max_len; /* maximum number of random bytes (allocated buffer size) */ size_t entropy; /* current entropy count in bits */ - size_t requested_entropy; /* requested entropy count in bits */ + size_t entropy_requested; /* requested entropy count in bits */ }; /* @@ -167,7 +193,7 @@ struct rand_drbg_st { unsigned short flags; /* various external flags */ /* - * The random pool is used by RAND_add()/drbg_add() to attach random + * The random_data is used by RAND_add()/drbg_add() to attach random * data to the global drbg, such that the rand_drbg_get_entropy() callback * can pull it during instantiation and reseeding. This is necessary to * reconcile the different philosophies of the RAND and the RAND_DRBG diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index e9bc952210..f40c513ce8 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -146,17 +146,11 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, return 0; } - pool = rand_pool_new(entropy, min_len, max_len); - if (pool == NULL) - return 0; - - if (drbg->pool) { - rand_pool_add(pool, - rand_pool_buffer(drbg->pool), - rand_pool_length(drbg->pool), - rand_pool_entropy(drbg->pool)); - rand_pool_free(drbg->pool); - drbg->pool = NULL; + if (drbg->pool != NULL) { + pool = drbg->pool; + pool->entropy_requested = entropy; + } else { + pool = rand_pool_new(entropy, min_len, max_len); } if (drbg->parent) { @@ -217,7 +211,10 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, void rand_drbg_cleanup_entropy(RAND_DRBG *drbg, unsigned char *out, size_t outlen) { - OPENSSL_secure_clear_free(out, outlen); + if (drbg->pool == NULL) + OPENSSL_secure_clear_free(out, outlen); + else + drbg->pool = NULL; } @@ -405,7 +402,7 @@ int RAND_poll(void) /* fill random pool and seed the current legacy RNG */ pool = rand_pool_new(RAND_DRBG_STRENGTH, RAND_DRBG_STRENGTH / 8, - DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8)); + RAND_POOL_MAX_LENGTH); if (pool == NULL) return 0; @@ -430,17 +427,18 @@ err: * Allocate memory and initialize a new random pool */ -RAND_POOL *rand_pool_new(int entropy, size_t min_len, size_t max_len) +RAND_POOL *rand_pool_new(int entropy_requested, size_t min_len, size_t max_len) { RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool)); if (pool == NULL) { RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE); - goto err; + return NULL; } pool->min_len = min_len; - pool->max_len = max_len; + pool->max_len = (max_len > RAND_POOL_MAX_LENGTH) ? + RAND_POOL_MAX_LENGTH : max_len; pool->buffer = OPENSSL_secure_zalloc(pool->max_len); if (pool->buffer == NULL) { @@ -448,7 +446,7 @@ RAND_POOL *rand_pool_new(int entropy, size_t min_len, size_t max_len) goto err; } - pool->requested_entropy = entropy; + pool->entropy_requested = entropy_requested; return pool; @@ -458,6 +456,38 @@ err: } /* + * Attach new random pool to the given buffer + * + * This function is intended to be used only for feeding random data + * provided by RAND_add() and RAND_seed() into the <master> DRBG. + */ +RAND_POOL *rand_pool_attach(const unsigned char *buffer, size_t len, + size_t entropy) +{ + RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool)); + + if (pool == NULL) { + RANDerr(RAND_F_RAND_POOL_ATTACH, ERR_R_MALLOC_FAILURE); + return NULL; + } + + /* + * The const needs to be cast away, but attached buffers will not be + * modified (in contrary to allocated buffers which are zeroed and + * freed in the end). + */ + pool->buffer = (unsigned char *) buffer; + pool->len = len; + + pool->attached = 1; + + pool->min_len = pool->max_len = pool->len; + pool->entropy = entropy; + + return pool; +} + +/* * Free |pool|, securely erasing its buffer. */ void rand_pool_free(RAND_POOL *pool) @@ -465,7 +495,14 @@ void rand_pool_free(RAND_POOL *pool) if (pool == NULL) return; - OPENSSL_secure_clear_free(pool->buffer, pool->max_len); + /* + * Although it would be advisable from a cryptographical viewpoint, + * we are not allowed to clear attached buffers, since they are passed + * to rand_pool_attach() as `const unsigned char*`. + * (see corresponding comment in rand_pool_attach()). + */ + if (!pool->attached) + OPENSSL_secure_clear_free(pool->buffer, pool->max_len); OPENSSL_free(pool); } @@ -524,7 +561,7 @@ unsigned char *rand_pool_detach(RAND_POOL *pool) */ size_t rand_pool_entropy_available(RAND_POOL *pool) { - if (pool->entropy < pool->requested_entropy) + if (pool->entropy < pool->entropy_requested) return 0; if (pool->len < pool->min_len) @@ -540,8 +577,8 @@ size_t rand_pool_entropy_available(RAND_POOL *pool) size_t rand_pool_entropy_needed(RAND_POOL *pool) { - if (pool->entropy < pool->requested_entropy) - return pool->requested_entropy - pool->entropy; + if (pool->entropy < pool->entropy_requested) + return pool->entropy_requested - pool->entropy; return 0; } diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c index e53b876dd3..cb3a6b24ab 100644 --- a/crypto/rand/rand_unix.c +++ b/crypto/rand/rand_unix.c @@ -264,7 +264,7 @@ static ssize_t syscall_random(void *buf, size_t buflen) * Note: 'buflen' equals the size of the buffer which is used by the * get_entropy() callback of the RAND_DRBG. It is roughly bounded by * - * 2 * DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^13 + * 2 * RAND_POOL_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^14 * * which is way below the OSSL_SSIZE_MAX limit. Therefore sign conversion * between size_t and ssize_t is safe even without a range check. |