summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorDr. Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>2018-10-21 15:45:34 +0200
committerDr. Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>2018-10-26 08:38:19 +0200
commit8817215d5c52a76f2b184b624bde4df8556dee6d (patch)
tree118f99760ecc7966a77d2f91347e3be79bb6c258 /crypto
parent6ec6448b9368b581d712514366c38b359ccff2f4 (diff)
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@oracle.com> (Merged from https://github.com/openssl/openssl/pull/7456)
Diffstat (limited to 'crypto')
-rw-r--r--crypto/rand/drbg_lib.c74
1 files changed, 69 insertions, 5 deletions
diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c
index 36b20c9398..9d920cb39a 100644
--- a/crypto/rand/drbg_lib.c
+++ b/crypto/rand/drbg_lib.c
@@ -1031,11 +1031,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;
@@ -1043,7 +1085,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
@@ -1052,13 +1118,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;