mirror of
https://github.com/clearml/dropbear
synced 2025-03-09 21:41:07 +00:00
Use Linux getrandom() to ensure random device is initialised
Remove old code warning about random device being not ready, /dev/random isn't used by default anyway.
This commit is contained in:
parent
5027bc4db1
commit
89e98a2f83
@ -370,7 +370,8 @@ AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \
|
|||||||
crypt.h \
|
crypt.h \
|
||||||
pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \
|
pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \
|
||||||
utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \
|
utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \
|
||||||
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h])
|
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \
|
||||||
|
sys/random.h])
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
@ -526,7 +527,7 @@ AC_CHECK_FUNCS(clock_gettime)
|
|||||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||||
AC_CHECK_FUNCS(mach_absolute_time)
|
AC_CHECK_FUNCS(mach_absolute_time)
|
||||||
|
|
||||||
AC_CHECK_FUNCS(explicit_bzero memset_s)
|
AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
|
||||||
|
|
||||||
AC_ARG_ENABLE(bundled-libtom,
|
AC_ARG_ENABLE(bundled-libtom,
|
||||||
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
|
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
|
||||||
|
146
dbrandom.c
146
dbrandom.c
@ -49,24 +49,19 @@ static int donerandinit = 0;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Pass len=0 to hash an entire file */
|
/* Pass wantlen=0 to hash an entire file */
|
||||||
static int
|
static int
|
||||||
process_file(hash_state *hs, const char *filename,
|
process_file(hash_state *hs, const char *filename,
|
||||||
unsigned int len, int prngd)
|
unsigned int wantlen, int prngd) {
|
||||||
{
|
|
||||||
static int already_blocked = 0;
|
|
||||||
int readfd;
|
int readfd;
|
||||||
unsigned int readcount;
|
unsigned int readcount;
|
||||||
int ret = DROPBEAR_FAILURE;
|
int ret = DROPBEAR_FAILURE;
|
||||||
|
|
||||||
|
if (prngd) {
|
||||||
#if DROPBEAR_USE_PRNGD
|
#if DROPBEAR_USE_PRNGD
|
||||||
if (prngd)
|
|
||||||
{
|
|
||||||
readfd = connect_unix(filename);
|
readfd = connect_unix(filename);
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
} else {
|
||||||
readfd = open(filename, O_RDONLY);
|
readfd = open(filename, O_RDONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,58 +70,31 @@ process_file(hash_state *hs, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
readcount = 0;
|
readcount = 0;
|
||||||
while (len == 0 || readcount < len)
|
while (wantlen == 0 || readcount < wantlen) {
|
||||||
{
|
|
||||||
int readlen, wantread;
|
int readlen, wantread;
|
||||||
unsigned char readbuf[4096];
|
unsigned char readbuf[4096];
|
||||||
if (!already_blocked && !prngd)
|
if (wantlen == 0) {
|
||||||
{
|
|
||||||
int res;
|
|
||||||
struct timeval timeout;
|
|
||||||
fd_set read_fds;
|
|
||||||
|
|
||||||
timeout.tv_sec = 2;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
|
|
||||||
DROPBEAR_FD_ZERO(&read_fds);
|
|
||||||
FD_SET(readfd, &read_fds);
|
|
||||||
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
|
||||||
if (res == 0)
|
|
||||||
{
|
|
||||||
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
|
|
||||||
already_blocked = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 0)
|
|
||||||
{
|
|
||||||
wantread = sizeof(readbuf);
|
wantread = sizeof(readbuf);
|
||||||
}
|
} else {
|
||||||
else
|
wantread = MIN(sizeof(readbuf), wantlen-readcount);
|
||||||
{
|
|
||||||
wantread = MIN(sizeof(readbuf), len-readcount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DROPBEAR_USE_PRNGD
|
#if DROPBEAR_USE_PRNGD
|
||||||
if (prngd)
|
if (prngd) {
|
||||||
{
|
|
||||||
char egdcmd[2];
|
char egdcmd[2];
|
||||||
egdcmd[0] = 0x02; /* blocking read */
|
egdcmd[0] = 0x02; /* blocking read */
|
||||||
egdcmd[1] = (unsigned char)wantread;
|
egdcmd[1] = (unsigned char)wantread;
|
||||||
if (write(readfd, egdcmd, 2) < 0)
|
if (write(readfd, egdcmd, 2) < 0) {
|
||||||
{
|
|
||||||
dropbear_exit("Can't send command to egd");
|
dropbear_exit("Can't send command to egd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
readlen = read(readfd, readbuf, wantread);
|
readlen = read(readfd, readbuf, wantread);
|
||||||
if (readlen <= 0) {
|
if (readlen <= 0) {
|
||||||
if (readlen < 0 && errno == EINTR) {
|
if (readlen < 0 && errno == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (readlen == 0 && len == 0)
|
if (readlen == 0 && wantlen == 0) {
|
||||||
{
|
|
||||||
/* whole file was read as requested */
|
/* whole file was read as requested */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -193,6 +161,63 @@ void fuzz_seed(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_GETRANDOM
|
||||||
|
/* Reads entropy seed with getrandom().
|
||||||
|
* May block if the kernel isn't ready.
|
||||||
|
* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||||
|
static int process_getrandom(hash_state *hs) {
|
||||||
|
char buf[INIT_SEED_SIZE];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
/* First try non-blocking so that we can warn about waiting */
|
||||||
|
ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK);
|
||||||
|
if (ret == -1) {
|
||||||
|
if (errno == ENOSYS) {
|
||||||
|
/* Old kernel */
|
||||||
|
return DROPBEAR_FAILURE;
|
||||||
|
}
|
||||||
|
/* Other errors fall through to blocking getrandom() */
|
||||||
|
TRACE(("first getrandom() failed: %d %s", errno, strerror(errno)))
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait blocking if needed. Loop in case we get EINTR */
|
||||||
|
while (ret != sizeof(buf)) {
|
||||||
|
ret = getrandom(buf, sizeof(buf), 0);
|
||||||
|
|
||||||
|
if (ret == sizeof(buf)) {
|
||||||
|
/* Success */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == -1 && errno == EINTR) {
|
||||||
|
/* Try again. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ret >= 0) {
|
||||||
|
TRACE(("Short read %zd from getrandom() shouldn't happen", ret))
|
||||||
|
/* Try again? */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unexpected problem, fall back to /dev/urandom */
|
||||||
|
TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == sizeof(buf)) {
|
||||||
|
/* Success, stir in the entropy */
|
||||||
|
sha1_process(hs, (void*)buf, sizeof(buf));
|
||||||
|
return DROPBEAR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DROPBEAR_FAILURE;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* HAVE_GETRANDOM */
|
||||||
|
|
||||||
/* Initialise the prng from /dev/urandom or prngd. This function can
|
/* Initialise the prng from /dev/urandom or prngd. This function can
|
||||||
* be called multiple times */
|
* be called multiple times */
|
||||||
void seedrandom() {
|
void seedrandom() {
|
||||||
@ -202,6 +227,7 @@ void seedrandom() {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
clock_t clockval;
|
clock_t clockval;
|
||||||
|
int urandom_seeded = 0;
|
||||||
|
|
||||||
#if DROPBEAR_FUZZ
|
#if DROPBEAR_FUZZ
|
||||||
if (fuzz.fuzzing) {
|
if (fuzz.fuzzing) {
|
||||||
@ -215,21 +241,31 @@ void seedrandom() {
|
|||||||
/* existing state */
|
/* existing state */
|
||||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||||
|
|
||||||
#if DROPBEAR_USE_PRNGD
|
#ifdef HAVE_GETRANDOM
|
||||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
|
||||||
!= DROPBEAR_SUCCESS) {
|
urandom_seeded = 1;
|
||||||
dropbear_exit("Failure reading random device %s",
|
|
||||||
DROPBEAR_PRNGD_SOCKET);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* non-blocking random source (probably /dev/urandom) */
|
|
||||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
|
||||||
!= DROPBEAR_SUCCESS) {
|
|
||||||
dropbear_exit("Failure reading random device %s",
|
|
||||||
DROPBEAR_URANDOM_DEV);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!urandom_seeded) {
|
||||||
|
#if DROPBEAR_USE_PRNGD
|
||||||
|
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||||
|
!= DROPBEAR_SUCCESS) {
|
||||||
|
dropbear_exit("Failure reading random device %s",
|
||||||
|
DROPBEAR_PRNGD_SOCKET);
|
||||||
|
urandom_seeded = 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* non-blocking random source (probably /dev/urandom) */
|
||||||
|
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||||
|
!= DROPBEAR_SUCCESS) {
|
||||||
|
dropbear_exit("Failure reading random device %s",
|
||||||
|
DROPBEAR_URANDOM_DEV);
|
||||||
|
urandom_seeded = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} /* urandom_seeded */
|
||||||
|
|
||||||
/* A few other sources to fall back on.
|
/* A few other sources to fall back on.
|
||||||
* Add more here for other platforms */
|
* Add more here for other platforms */
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
@ -124,6 +124,10 @@
|
|||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_RANDOM_H
|
||||||
|
#include <sys/random.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BUNDLED_LIBTOM
|
#ifdef BUNDLED_LIBTOM
|
||||||
#include "libtomcrypt/src/headers/tomcrypt.h"
|
#include "libtomcrypt/src/headers/tomcrypt.h"
|
||||||
#include "libtommath/tommath.h"
|
#include "libtommath/tommath.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user