On 18 July 2018 at 03:17, Michael Paquier <[email protected]> wrote:
>> [1] https://wiki.openssl.org/index.php/Random_Numbers
>
> This quote from the wiki is scary so that's not quite clean either for
> Windows:
> "Be careful when deferring to RAND_poll on some Unix systems because it
> does not seed the generator. See the code guarded with
> OPENSSL_SYS_VXWORKS in rand_unix.c. Additionally, RAND_poll can have
> negative interactions on newer Windows platforms, so your program could
> hang or crash depending on the potential issue. See Windows Issues
> below."
>
I think that wiki page is somewhat out of date in places. Both the
Windows issues it links to seem to have been fixed a long time ago, so
I think using RAND_poll() is probably safe now, although perhaps there
are still some Unix platforms on which it won't help either.
>> [2]
>> https://github.com/benvanik/openssl/blob/master/openssl/crypto/rand/md_rand.c
>
> This repository is outdated, on OpenSSL HEAD I am seeing this used only
> in rand_win.c. And this commit is sort of interesting because there was
> a retry loop done with RAND_poll(). Please see this one:
> commit: c16de9d8329d41a2433d0f273c080d9d06ad7a87
> author: Dr. Matthias St. Pierre <[email protected]>
> date: Thu, 31 Aug 2017 23:16:22 +0200
> committer: Ben Kaduk <[email protected]>
> date: Wed, 18 Oct 2017 08:39:20 -0500
> Fix reseeding issues of the public RAND_DRBG
>
> apps/ocsp.c also has the wisdom to check for a failure on RAND_poll().
OK, I guess that it is possible that an older version of OpenSSL
requires RAND_poll() to be called multiple times. Here's an updated
patch doing that (with up to 8 retries, based on the old OpenSSL
code).
Regards,
Dean
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
new file mode 100644
index bc7a8aa..a2ab8c1
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -103,6 +103,37 @@ pg_strong_random(void *buf, size_t len)
* When built with OpenSSL, use OpenSSL's RAND_bytes function.
*/
#if defined(USE_OPENSSL_RANDOM)
+ /*
+ * Check that OpenSSL's CSPRNG has been sufficiently seeded, and if not
+ * add more seed data using RAND_poll(). With some older versions of
+ * OpenSSL, it may be necessary to call RAND_poll() a number of times.
+ */
+#define NUM_RAND_POLL_RETRIES 8
+
+ if (RAND_status() == 0)
+ {
+ int i;
+
+ for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
+ {
+ if (RAND_poll() == 0)
+ {
+ /*
+ * RAND_poll() failed to generate any seed data, which means
+ * that RAND_bytes() will probably fail. For now, just fall
+ * through and let that happen. XXX: maybe we could seed it
+ * some other way.
+ */
+ break;
+ }
+
+ if (RAND_status() == 1)
+ {
+ /* The CSPRNG is now sufficiently seeded */
+ break;
+ }
+ }
+ }
if (RAND_bytes(buf, len) == 1)
return true;
return false;