@@ -85,14 +85,36 @@ class CInit
8585 ppmutexOpenSSL[i] = new CCriticalSection ();
8686 CRYPTO_set_locking_callback (locking_callback);
8787
88- #ifdef WIN32
89- // Seed OpenSSL PRNG with current contents of the screen
90- RAND_screen ();
91- #endif
88+ // Check whether OpenSSL random number generator is properly seeded. If not, attempt to seed using RAND_poll().
89+ // Note that in versions of OpenSSL in the depends in Gridcoin (currently 1.1.1+), and modern Unix distros (using
90+ // openSSL 1.1+ or modern Windows operating systems with the equivalent of /dev/urandom, the random number
91+ // generator is automatically seeded on init, and periodically reseeded from trusted OS random sources. It is
92+ // not necessary to manually reseed the RNG. Here we implement a check via RAND_status() to ensure the RNG
93+ // is properly seeded. If not, we try 10 times (probably excessive) to seed the RNG via openSSL's entropy sources,
94+ // breaking as soon as the return from RAND_poll() becomes 1 (successfully seeded). A 100 ms sleep is inserted
95+ // between each try to ensure we give time for a short term unavailability of the OS entropy source to recover.
96+ // If this falls through, we abort the application as we cannot have a non-functioning RNG.
97+ bool seed_successful = RAND_status ();
98+ if (!seed_successful) {
99+ for (unsigned int i = 0 ; i < 10 ; ++i)
100+ {
101+ seed_successful = RAND_poll ();
102+
103+ if (seed_successful) break ;
104+
105+ MilliSleep (100 );
106+ }
92107
93- // Seed OpenSSL PRNG with performance counter
94- RandAddSeed ();
108+ if (!seed_successful) {
109+ tfm::format (std::cerr, " ERROR: %s: Unable to initialize the random number generator. Cannot continue. "
110+ " Please check your operating system to ensure the random number source is "
111+ " available. (This is /dev/urandom on Linux.)" ,
112+ __func__);
113+ std::abort ();
114+ }
115+ }
95116 }
117+
96118 ~CInit ()
97119 {
98120 // Securely erase the memory used by the PRNG
@@ -118,13 +140,15 @@ void RandAddSeedPerfmon()
118140{
119141 RandAddSeed ();
120142
143+ // Only need for OpenSSL < 1.1 and Win32, since 1.1 and greater seed properly from Windows, and on Linux seeds properly
144+ // in all cases.
145+ #if OPENSSL_VERSION_NUMBER < 0x10100000L && defined(WIN32)
121146 // This can take up to 2 seconds, so only do it every 10 minutes
122147 static int64_t nLastPerfmon;
123148 if ( GetAdjustedTime () < nLastPerfmon + 10 * 60 )
124149 return ;
125150 nLastPerfmon = GetAdjustedTime ();
126151
127- #ifdef WIN32
128152 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
129153 // Seed with the entire set of perfmon data
130154 unsigned char pdata[250000 ];
0 commit comments