Fixes #7240
In FIPS mode, the default FIPS DRBG uses the drbg_get_entropy()
callback to reseed itself, which is provided by the wrapping
libcrypto library. This callback in turn uses ssleay_rand_bytes()
to generate random bytes.
Now ssleay_rand_bytes() calls RAND_poll() once on first call to
seed itself, but RAND_poll() is never called again (unless the
application calls RAND_poll() explicitely). This implies that
whenever the DRBG reseeds itself (which happens every 2^14
generate requests) this happens without obtaining fresh random
data from the operating system's entropy sources.
This patch forces a reseed from system entropy sources on every
call to drbg_get_entropy(). In contrary to the automatic reseeding
of the DRBG in master, this reseeding does not break applications
running in a chroot() environment (see
c7504aeb640a), because the
SSLEAY PRNG does not maintain an error state. (It does not even
check the return value of RAND_poll() on its instantiation.)
In the worst case, if no random device is available for reseeding,
no fresh entropy will be added to the SSLEAY PRNG but it will happily
continue to generate random bytes as 'entropy' input for the DRBG's
reseeding, which is just as good (or bad) as before this patch.
To prevent ssleay_rand_bytes_from_system() (and hence RAND_poll())
from being called twice during instantiation, a separate
drbg_get_nonce() callback has been introduced, which is identical
with the previous implementation of drbg_get_entropy().
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Ben Kaduk <kaduk@mit.edu>
(Merged from https://github.com/openssl/openssl/pull/7259)
return (0);
}
+/*
+ * Returns ssleay_rand_bytes(), enforcing a reseeding from the
+ * system entropy sources using RAND_poll() before generating
+`* the random bytes.
+ */
+
+int ssleay_rand_bytes_from_system(unsigned char *buf, int num)
+{
+ initialized = 0;
+ return ssleay_rand_bytes(buf, num, 0, 0);
+}
+
static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num)
{
return ssleay_rand_bytes(buf, num, 0, 1);
# endif
int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo, int lock);
-
+int ssleay_rand_bytes_from_system(unsigned char *buf, int num);
#endif
/*
* Entropy gatherer: use standard OpenSSL PRNG to seed (this will gather
- * entropy internally through RAND_poll().
+ * entropy internally through RAND_poll()).
*/
static size_t drbg_get_entropy(DRBG_CTX *ctx, unsigned char **pout,
int entropy, size_t min_len, size_t max_len)
+{
+ /* Round up request to multiple of block size */
+ min_len = ((min_len + 19) / 20) * 20;
+ *pout = OPENSSL_malloc(min_len);
+ if (!*pout)
+ return 0;
+
+ /* Enforces a reseed of the SSLEAY PRNG before generating random bytes */
+ if (ssleay_rand_bytes_from_system(*pout, min_len) <= 0) {
+ OPENSSL_free(*pout);
+ *pout = NULL;
+ return 0;
+ }
+ return min_len;
+}
+
+static size_t drbg_get_nonce(DRBG_CTX *ctx, unsigned char **pout,
+ int entropy, size_t min_len, size_t max_len)
{
/* Round up request to multiple of block size */
min_len = ((min_len + 19) / 20) * 20;
FIPS_drbg_set_callbacks(dctx,
drbg_get_entropy, drbg_free_entropy, 20,
- drbg_get_entropy, drbg_free_entropy);
+ drbg_get_nonce, drbg_free_entropy);
FIPS_drbg_set_rand_callbacks(dctx, drbg_get_adin, 0,
drbg_rand_seed, drbg_rand_add);
/* Personalisation string: a string followed by date time vector */