Skip to content

Commit 9fa0199

Browse files
committed
random: add WC_RNG_SEED_DEVICE to seed from a nominated device
1 parent 437bca8 commit 9fa0199

5 files changed

Lines changed: 108 additions & 17 deletions

File tree

.github/configs/os-check-linux.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@
268268
{"name": "no-verify-oid-fpki", "minutes": 1.2,
269269
"configure": ["CPPFLAGS=-DNO_VERIFY_OID -DWOLFSSL_FPKI"]},
270270
{"name": "no-verify-oid", "minutes": 1.1, "configure": ["CPPFLAGS=-DNO_VERIFY_OID"]},
271+
{"name": "rng-seed-device", "minutes": 1.1,
272+
"comment": "Seed the RNG from a nominated device. /dev/urandom stands in for a hardware RNG so the WC_RNG_SEED_DEVICE read path is actually exercised on a runner.",
273+
"configure": ["--with-rng-seed-device=/dev/urandom"]},
274+
{"name": "rng-seed-device-fallback", "minutes": 1.1,
275+
"comment": "Nominated seed device that cannot be opened, so every test runs through the fallback to the default seed sources.",
276+
"configure": ["--with-rng-seed-device=/nonexistent/hwrng"]},
271277
{"name": "no-server-no-client-auth", "minutes": 1.0,
272278
"configure": ["CPPFLAGS=-DNO_WOLFSSL_SERVER -DWOLFSSL_NO_CLIENT_AUTH"]},
273279
{"name": "no-wolfssl-client", "minutes": 1.0,

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3768,6 +3768,14 @@ if(WOLFSSL_ECC AND WOLFSSL_ECC_MIN_KEY_SZ)
37683768
list(APPEND WOLFSSL_DEFINITIONS "-DECC_MIN_KEY_SZ=${WOLFSSL_ECC_MIN_KEY_SZ}")
37693769
endif()
37703770

3771+
# RNG seed device (best effort, falls back to the default sources)
3772+
set(WOLFSSL_RNG_SEED_DEVICE "" CACHE STRING
3773+
"Seed the RNG from this device before the default sources, e.g. /dev/hwrng (default: disabled)")
3774+
if(WOLFSSL_RNG_SEED_DEVICE)
3775+
list(APPEND WOLFSSL_DEFINITIONS
3776+
"-DWC_RNG_SEED_DEVICE=\"${WOLFSSL_RNG_SEED_DEVICE}\"")
3777+
endif()
3778+
37713779

37723780
####################################################
37733781
# Additional crypto/TLS feature options (parity with configure.ac)

cmake/options.h.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ extern "C" {
611611
#cmakedefine MAX_EX_DATA @MAX_EX_DATA@
612612
#undef ECC_MIN_KEY_SZ
613613
#cmakedefine ECC_MIN_KEY_SZ @ECC_MIN_KEY_SZ@
614+
#undef WC_RNG_SEED_DEVICE
615+
#cmakedefine WC_RNG_SEED_DEVICE @WC_RNG_SEED_DEVICE@
614616

615617
/* parity: crypto/TLS feature options (wave B) */
616618
#undef WOLFSSL_MD2

configure.ac

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8749,6 +8749,23 @@ then
87498749
fi
87508750
87518751
8752+
# RNG seed device (best effort, falls back to the default sources)
8753+
AC_ARG_WITH([rng-seed-device],
8754+
[AS_HELP_STRING([--with-rng-seed-device=PATH],[Seed the RNG from PATH before the default sources, e.g. /dev/hwrng (default: disabled)])],
8755+
[ RNG_SEED_DEVICE=$withval ],
8756+
[ RNG_SEED_DEVICE=no ]
8757+
)
8758+
8759+
if test "$RNG_SEED_DEVICE" != "no"
8760+
then
8761+
if test "$RNG_SEED_DEVICE" = "yes"
8762+
then
8763+
RNG_SEED_DEVICE="/dev/hwrng"
8764+
fi
8765+
AM_CFLAGS="$AM_CFLAGS -DWC_RNG_SEED_DEVICE=\\\"$RNG_SEED_DEVICE\\\""
8766+
fi
8767+
8768+
87528769
# Filesystem Build
87538770
if test "$HAVE_KERNEL_MODE" = "yes"
87548771
then

wolfcrypt/src/random.c

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ This library contains implementation for the random number generator.
5858
* FORCE_FAILURE_GETRANDOM: Force getrandom failure (testing) default: off
5959
* NO_DEV_RANDOM: Don't use /dev/random for seeding default: off
6060
* NO_DEV_URANDOM: Don't use /dev/urandom for seeding default: off
61+
* WC_RNG_SEED_DEVICE: Device tried before the usual seed default: off
62+
* sources. Must be a quoted string,
63+
* e.g. -DWC_RNG_SEED_DEVICE='"/dev/hwrng"'
6164
* HAVE_INTEL_RDRAND: Use Intel RDRAND instruction default: off
6265
* HAVE_INTEL_RDSEED: Use Intel RDSEED instruction default: off
6366
* HAVE_AMD_RDSEED: Use AMD RDSEED instruction default: off
@@ -352,6 +355,11 @@ enum {
352355
#error RNG_MAX_BLOCK_LEN is larger than NIST DBRG max request length
353356
#endif
354357

358+
/* the seed device is read through the filesystem API */
359+
#if defined(WC_RNG_SEED_DEVICE) && defined(NO_FILESYSTEM)
360+
#error WC_RNG_SEED_DEVICE requires filesystem support
361+
#endif
362+
355363
enum {
356364
drbgInitC = 0,
357365
drbgReseed = 1,
@@ -5933,6 +5941,12 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
59335941
int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
59345942
{
59355943
int ret = 0;
5944+
#ifdef WC_RNG_SEED_DEVICE
5945+
byte* devOut;
5946+
word32 devSz;
5947+
int devFd;
5948+
int devLen;
5949+
#endif
59365950

59375951
/* Validate output before any entropy backend dereferences it: some
59385952
* (e.g. glibc's vDSO getrandom()) fault on a NULL buffer rather than
@@ -5971,6 +5985,43 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
59715985

59725986
#if !defined(HAVE_ENTROPY_MEMUSE) || !defined(ENTROPY_MEMUSE_FORCE_FAILURE)
59735987

5988+
#ifdef WC_RNG_SEED_DEVICE
5989+
/* Nominated entropy source, usually a hardware RNG. Best effort: on
5990+
* any failure fall through to the default sources below. Those refill
5991+
* the whole request from the start, so bytes a partial read left in
5992+
* output are overwritten rather than mixed in. */
5993+
devOut = output;
5994+
devSz = sz;
5995+
devFd = wc_open_cloexec(WC_RNG_SEED_DEVICE, O_RDONLY);
5996+
if (devFd != XBADFD) {
5997+
while (devSz > 0) {
5998+
errno = 0;
5999+
devLen = (int)read(devFd, devOut, devSz);
6000+
if (devLen < 0) {
6001+
if (errno == EINTR)
6002+
continue; /* interrupted, read again */
6003+
break;
6004+
}
6005+
if (devLen == 0)
6006+
break; /* at EOF, will never fill the request */
6007+
6008+
devSz -= (word32)devLen;
6009+
devOut += devLen;
6010+
}
6011+
close(devFd);
6012+
}
6013+
#if defined(DEBUG_WOLFSSL)
6014+
if (devSz == 0)
6015+
WOLFSSL_MSG("seeded from WC_RNG_SEED_DEVICE.");
6016+
else
6017+
WOLFSSL_MSG("WC_RNG_SEED_DEVICE unusable, using default.");
6018+
#endif /* DEBUG_WOLFSSL */
6019+
if (devSz == 0) {
6020+
/* success, we're done */
6021+
return 0;
6022+
}
6023+
#endif /* WC_RNG_SEED_DEVICE */
6024+
59746025
#if defined(HAVE_INTEL_RDSEED) || defined(HAVE_AMD_RDSEED)
59756026
if (IS_INTEL_RDSEED(intel_flags)) {
59766027
ret = wc_GenerateSeed_IntelRD(NULL, output, sz);
@@ -6038,44 +6089,50 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
60386089
#ifdef WOLFSSL_KEEP_RNG_SEED_FD_OPEN
60396090
if (!os->seedFdOpen)
60406091
{
6092+
os->fd = XBADFD;
60416093
#ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */
6042-
os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY);
6094+
if (os->fd == XBADFD) {
6095+
os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY);
60436096
#if defined(DEBUG_WOLFSSL)
6044-
WOLFSSL_MSG("opened /dev/urandom.");
6097+
if (os->fd != XBADFD)
6098+
WOLFSSL_MSG("opened /dev/urandom.");
60456099
#endif /* DEBUG_WOLFSSL */
6046-
if (os->fd == XBADFD)
6100+
}
60476101
#endif /* NO_DEV_URANDOM */
6048-
{
6102+
if (os->fd == XBADFD) {
60496103
/* may still have /dev/random */
60506104
os->fd = wc_open_cloexec("/dev/random", O_RDONLY);
60516105
#if defined(DEBUG_WOLFSSL)
6052-
WOLFSSL_MSG("opened /dev/random.");
6106+
if (os->fd != XBADFD)
6107+
WOLFSSL_MSG("opened /dev/random.");
60536108
#endif /* DEBUG_WOLFSSL */
60546109
if (os->fd == XBADFD)
60556110
return OPEN_RAN_E;
6056-
else {
6057-
os->keepSeedFdOpen = 0;
6058-
os->seedFdOpen = 1;
6059-
}
6111+
os->keepSeedFdOpen = 0;
6112+
os->seedFdOpen = 1;
60606113
}
60616114
else {
60626115
os->keepSeedFdOpen = 1;
60636116
os->seedFdOpen = 1;
60646117
}
60656118
}
60666119
#else /* WOLFSSL_KEEP_RNG_SEED_FD_OPEN */
6067-
#ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */
6068-
os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY);
6120+
os->fd = XBADFD;
6121+
#ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */
6122+
if (os->fd == XBADFD) {
6123+
os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY);
60696124
#if defined(DEBUG_WOLFSSL)
6070-
WOLFSSL_MSG("opened /dev/urandom.");
6125+
if (os->fd != XBADFD)
6126+
WOLFSSL_MSG("opened /dev/urandom.");
60716127
#endif /* DEBUG_WOLFSSL */
6072-
if (os->fd == XBADFD)
6073-
#endif /* !NO_DEV_URANDOM */
6074-
{
6128+
}
6129+
#endif /* !NO_DEV_URANDOM */
6130+
if (os->fd == XBADFD) {
60756131
/* may still have /dev/random */
60766132
os->fd = wc_open_cloexec("/dev/random", O_RDONLY);
60776133
#if defined(DEBUG_WOLFSSL)
6078-
WOLFSSL_MSG("opened /dev/random.");
6134+
if (os->fd != XBADFD)
6135+
WOLFSSL_MSG("opened /dev/random.");
60796136
#endif /* DEBUG_WOLFSSL */
60806137
if (os->fd == XBADFD)
60816138
return OPEN_RAN_E;
@@ -6086,7 +6143,8 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
60866143
#endif /* DEBUG_WOLFSSL */
60876144
while (sz) {
60886145
int len = (int)read(os->fd, output, sz);
6089-
if (len == -1) {
6146+
/* EOF never fills the request, don't retry forever */
6147+
if (len <= 0) {
60906148
ret = READ_RAN_E;
60916149
break;
60926150
}

0 commit comments

Comments
 (0)