Skip to content

Commit 807e60c

Browse files
committed
Make improvements to RNG code in we_random.c.
Remove we_rand_bytes and always use we_rand_pseudorand for RAND_METHOD's "bytes" function. we_rand_bytes was using wc_GenerateSeed to provide true entropy for older versions of OpenSSL. With this commit, both the bytes and pseudorand members of wolfEngine's RAND_METHOD map to the same function, which was already the case if using wolfEngine with an OpenSSL version after 1.1.0. This commit renames we_rand_pseudorand to we_rand_bytes. Additionally, I've augmented the new unified function to mix in the thread ID, a timer value, and PID to add some additional weak entropy. These changes resolve an issue with OpenSSH where we_rand_bytes was being called in a forked process that didn't have the ability to open /dev/urandom, which wc_GenerateSeed will attempt to do.
1 parent 0e78a64 commit 807e60c

File tree

2 files changed

+119
-80
lines changed

2 files changed

+119
-80
lines changed

include/wolfengine/we_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include <openssl/cmac.h>
6363
#endif
6464
#include <openssl/pkcs12.h>
65+
#include <openssl/crypto.h>
6566

6667
#ifndef WOLFENGINE_USER_SETTINGS
6768
#include <wolfssl/options.h>

src/we_random.c

Lines changed: 118 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@
2020
*/
2121

2222
#include <wolfengine/we_internal.h>
23+
#ifndef _WIN32
24+
#include <sys/time.h>
25+
#endif /* !_WIN32 */
2326

2427
#ifdef WE_HAVE_RANDOM
2528

2629
#ifdef WE_STATIC_WOLFSSL
2730
extern int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz);
28-
#if OPENSSL_VERSION_NUMBER < 0x10100000L
29-
extern int wc_GenerateSeed(OS_Seed* os, byte* seed, int sz);
30-
#endif
3131
#else
3232
/* Hash of all the seed so far. */
3333
unsigned char we_seed[WC_SHA256_DIGEST_SIZE] = {0,};
@@ -45,7 +45,7 @@ int haveSeed = 0;
4545
* @param num [in] Number of random bytes.
4646
* @param seed [in] Buffer holding seed data.
4747
* @param seedLen [in] Number of seed bytes.
48-
* @returns 1 when successful and 0 on fauilure.
48+
* @returns 1 when successful and 0 on failure.
4949
*/
5050
static int we_rand_mix_seed(unsigned char* buf, int num,
5151
const unsigned char* seed, int seedLen)
@@ -203,72 +203,6 @@ static int we_rand_seed(const void *buf, int num)
203203
#endif
204204
}
205205

206-
/* Note: from OpensSL 1.1.0 onwards RAND_bytes no longer gets true entropy.
207-
* There are public and private randoms that are each seeded from entropy.
208-
* No way to tell when RAND_priv_rand() is called with methods.
209-
* Use pseudo-bytes implementation when RAND_bytes(), RAND_priv_bytes() and
210-
* RAND_pseudo_bytes() are called.
211-
*/
212-
#if OPENSSL_VERSION_NUMBER < 0x10100000L
213-
/**
214-
* Generate true random.
215-
*
216-
* @param buf [out] Buffer to hold random.
217-
* @param num [in] Number of bytes to generate.
218-
* @returns 1 when data generated and 0 on failure.
219-
*/
220-
static int we_rand_bytes(unsigned char *buf, int num)
221-
{
222-
int ret = 1;
223-
int rc;
224-
#ifdef WE_STATIC_WOLFSSL
225-
OS_Seed os;
226-
#else
227-
WC_RNG rng;
228-
#endif
229-
230-
WOLFENGINE_ENTER(WE_LOG_RNG, "we_rand_bytes");
231-
WOLFENGINE_MSG_VERBOSE(WE_LOG_RNG, "ARGS [buf = %p, num = %d]", buf, num);
232-
233-
#ifdef WE_STATIC_WOLFSSL
234-
/* Generate true random using internal API. */
235-
rc = wc_GenerateSeed(&os, buf, num);
236-
if (rc != 0) {
237-
WOLFENGINE_ERROR_FUNC(WE_LOG_RNG, "wc_GenerateSeed", rc);
238-
ret = 0;
239-
}
240-
241-
#else
242-
/* Create a new random number generator that is seeded with true random. */
243-
rc = wc_InitRng(&rng);
244-
if (rc != 0) {
245-
WOLFENGINE_ERROR_FUNC(WE_LOG_RNG, "wc_InitRng", rc);
246-
ret = 0;
247-
}
248-
else {
249-
/* Generate true random. */
250-
rc = wc_RNG_GenerateBlock(&rng, buf, num);
251-
if (rc != 0) {
252-
WOLFENGINE_ERROR_FUNC(WE_LOG_RNG, "wc_RNG_GenerateBlock", rc);
253-
ret = 0;
254-
}
255-
256-
/* Dispose of random number generator. */
257-
rc = wc_FreeRng(&rng);
258-
if (rc != 0) {
259-
WOLFENGINE_ERROR_FUNC(WE_LOG_RNG, "wc_FreeRng", rc);
260-
ret = 0;
261-
}
262-
}
263-
264-
#endif
265-
266-
WOLFENGINE_LEAVE(WE_LOG_RNG, "we_rand_bytes", ret);
267-
268-
return ret;
269-
}
270-
#endif
271-
272206
static void we_rand_cleanup(void)
273207
{
274208
/* Global random cleanup done in internal.c: we_final_random(). */
@@ -312,19 +246,115 @@ static int we_rand_add(const void *buf, int num, double entropy)
312246
#endif
313247
}
314248

249+
#ifndef WE_STATIC_WOLFSSL
250+
/**
251+
* Add weak entropy to the input buffer. Used by we_rand_bytes to add entropy
252+
* for RNG. Uses thread ID, a timer value, and PID.
253+
*
254+
* @param buf [in] Input buffer to mix with generated entropy.
255+
* @param num [in] Length of input buffer.
256+
* @returns 1 on success, 0 on failure.
257+
*/
258+
static int we_rand_add_weak_entropy(unsigned char* buf, int num)
259+
{
260+
int ret = 1;
261+
unsigned char* idx;
262+
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
263+
CRYPTO_THREAD_ID threadId;
264+
#else
265+
CRYPTO_THREADID threadId;
266+
unsigned long threadIdHash;
267+
#endif /* OPENSSL_VERSION_NUMBER >= 0x1010000fL */
268+
#ifndef _WIN32
269+
struct timeval tv;
270+
unsigned long timer;
271+
pid_t pid;
272+
#else
273+
LARGE_INTEGER timer;
274+
DWORD pid;
275+
#endif /* !_WIN32 */
276+
277+
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
278+
threadId = CRYPTO_THREAD_get_current_id();
279+
unsigned char addEntropy[sizeof(threadId) + sizeof(timer) + sizeof(pid)];
280+
#else
281+
CRYPTO_THREADID_current(&threadId);
282+
threadIdHash = CRYPTO_THREADID_hash(&threadId);
283+
unsigned char addEntropy[sizeof(threadIdHash) + sizeof(timer) +
284+
sizeof(pid)];
285+
#endif /* OPENSSL_VERSION_NUMBER >= 0x1010000fL */
286+
const size_t addEntropySz = sizeof(addEntropy);
287+
288+
WOLFENGINE_ENTER(WE_LOG_RNG, "we_rand_add_weak_entropy");
289+
WOLFENGINE_MSG_VERBOSE(WE_LOG_RNG, "ARGS [buf = %p, num = %d]", buf, num);
290+
291+
if (buf == NULL || num <= 0) {
292+
WOLFENGINE_ERROR_MSG(WE_LOG_RNG, "Bad argument.");
293+
ret = 0;
294+
}
295+
296+
if (ret == 1) {
297+
#ifndef _WIN32
298+
if (gettimeofday(&tv, NULL) != 0) {
299+
WOLFENGINE_ERROR_MSG(WE_LOG_RNG, "gettimeofday for additional "
300+
"entropy failed");
301+
ret = 0;
302+
}
303+
else {
304+
timer = 1000000 * tv.tv_sec + tv.tv_usec; /* time in us */
305+
pid = getpid();
306+
}
307+
#else
308+
ret = QueryPerformanceCounter(&timer);
309+
if (ret == 0) {
310+
WOLFENGINE_ERROR_MSG(WE_LOG_RNG, "QueryPerformanceCounter for "
311+
"additional entropy failed");
312+
}
313+
else {
314+
pid = GetCurrentProcessId();
315+
}
316+
#endif /* !_WIN32 */
317+
}
318+
319+
if (ret == 1) {
320+
idx = addEntropy;
321+
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
322+
XMEMCPY(idx, (unsigned char*)&threadId, sizeof(threadId));
323+
idx += sizeof(threadId);
324+
#else
325+
XMEMCPY(idx, (unsigned char*)&threadIdHash, sizeof(threadIdHash));
326+
idx += sizeof(threadIdHash);
327+
#endif /* OPENSSL_VERSION_NUMBER >= 0x1010000fL */
328+
XMEMCPY(idx, (unsigned char*)&timer, sizeof(timer));
329+
idx += sizeof(timer);
330+
XMEMCPY(idx, (unsigned char*)&pid, sizeof(pid));
331+
332+
ret = we_rand_mix_seed(buf, num, addEntropy, addEntropySz);
333+
if (ret != 1) {
334+
WOLFENGINE_ERROR_MSG(WE_LOG_RNG, "we_rand_mix_seed with weak "
335+
"entropy failed");
336+
}
337+
}
338+
339+
WOLFENGINE_LEAVE(WE_LOG_RNG, "we_rand_add_weak_entropy", ret);
340+
341+
return ret;
342+
}
343+
#endif /* WE_STATIC_WOLFSSL */
344+
315345
/**
316346
* Generate pseudo-random data.
317347
*
318348
* @param buf [out] Buffer to fill with random.
319349
* @param num [in] Number of bytes to generate.
320350
* @returns 1 when data generated and 0 on failure.
321351
*/
322-
static int we_rand_pseudorand(unsigned char *buf, int num)
352+
static int we_rand_bytes(unsigned char *buf, int num)
323353
{
324354
int ret = 1;
325355
int rc;
326356

327-
WOLFENGINE_ENTER(WE_LOG_RNG, "we_rand_pseudorand");
357+
WOLFENGINE_ENTER(WE_LOG_RNG, "we_rand_bytes");
328358
WOLFENGINE_MSG_VERBOSE(WE_LOG_RNG, "ARGS [buf = %p, num = %d]",
329359
buf, num);
330360

@@ -346,14 +376,27 @@ static int we_rand_pseudorand(unsigned char *buf, int num)
346376
/* Mix global seed if RAND_add() or RAND_seed() has been called. */
347377
if (haveSeed) {
348378
ret = we_rand_mix_seed(buf, num, we_seed, sizeof(we_seed));
379+
if (ret != 1) {
380+
WOLFENGINE_ERROR_MSG(WE_LOG_RNG, "we_rand_mix_seed with global "
381+
"seed failed");
382+
}
349383
}
350-
#endif
384+
/* Mix in weak entropy. */
385+
if (ret == 1) {
386+
ret = we_rand_add_weak_entropy(buf, num);
387+
if (ret != 1) {
388+
WOLFENGINE_ERROR_MSG(WE_LOG_RNG, "we_rand_mix_seed with "
389+
"weak entropy failed");
390+
}
391+
}
392+
#endif /* !WE_STATIC_WOLFSSL */
393+
351394
#ifndef WE_SINGLE_THREADED
352395
wc_UnLockMutex(we_rng_mutex);
353396
#endif
354397
}
355398

356-
WOLFENGINE_LEAVE(WE_LOG_RNG, "we_rand_pseudorand", ret);
399+
WOLFENGINE_LEAVE(WE_LOG_RNG, "we_rand_bytes", ret);
357400

358401
return ret;
359402
}
@@ -377,15 +420,10 @@ static int we_rand_status(void)
377420
*/
378421
RAND_METHOD we_rand_method ={
379422
we_rand_seed,
380-
#if OPENSSL_VERSION_NUMBER < 0x10100000L
381423
we_rand_bytes,
382-
#else
383-
/* See note above we_rand_bytes. */
384-
we_rand_pseudorand,
385-
#endif
386424
we_rand_cleanup,
387425
we_rand_add,
388-
we_rand_pseudorand,
426+
we_rand_bytes,
389427
we_rand_status,
390428
};
391429

0 commit comments

Comments
 (0)