libmisc/salt.c: Obtain random bytes from /dev/urandom.

Using the random() function to obtain pseudo-random bytes
for generating salt strings is considered to be dangerous.
See CWE-327.

We really should use a more reliable source for obtaining
pseudo-random bytes like /dev/urandom.

Fixes #376.

Signed-off-by: Björn Esser <besser82@fedoraproject.org>
This commit is contained in:
Björn Esser 2021-06-23 16:06:47 +02:00
parent dbf230e4cf
commit bc8257cf73
No known key found for this signature in database
GPG Key ID: F52E98007594C21D

View File

@ -11,11 +11,10 @@
#ident "$Id$" #ident "$Id$"
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "prototypes.h" #include "prototypes.h"
#include "defines.h" #include "defines.h"
#include "getdef.h" #include "getdef.h"
@ -74,7 +73,7 @@
#define GENSALT_SETTING_SIZE 100 #define GENSALT_SETTING_SIZE 100
/* local function prototypes */ /* local function prototypes */
static void seedRNG (void); static long read_random_bytes (void);
static /*@observer@*/const char *gensalt (size_t salt_size); static /*@observer@*/const char *gensalt (size_t salt_size);
#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
static long shadow_random (long min, long max); static long shadow_random (long min, long max);
@ -125,23 +124,27 @@ static /*@observer@*/char *l64a (long value)
} }
#endif /* !HAVE_L64A */ #endif /* !HAVE_L64A */
static void seedRNG (void) /* Read sizeof (long) random bytes from /dev/urandom. */
static long read_random_bytes (void)
{ {
struct timeval tv; long randval = 0;
static int seeded = 0; FILE *f = fopen ("/dev/urandom", "r");
if (0 == seeded) { if (fread (&randval, sizeof (randval), 1, f) != sizeof (randval))
(void) gettimeofday (&tv, NULL); {
srandom (tv.tv_sec ^ tv.tv_usec ^ getpid ()); fprintf (shadow_logfd,
seeded = 1; _("Unable to read from /dev/urandom.\n"));
fclose(f);
exit (1);
} }
fclose(f);
return randval;
} }
#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
/* It is not clear what is the maximum value of random().
* We assume 2^31-1.*/
#define RANDOM_MAX 0x7FFFFFFF
/* /*
* Return a random number between min and max (both included). * Return a random number between min and max (both included).
* *
@ -151,8 +154,9 @@ static long shadow_random (long min, long max)
{ {
double drand; double drand;
long ret; long ret;
seedRNG ();
drand = (double) (max - min + 1) * random () / RANDOM_MAX; drand = (double) (read_random_bytes () & RAND_MAX) / (double) RAND_MAX;
drand *= (double) (max - min + 1);
/* On systems were this is not random() range is lower, we favor /* On systems were this is not random() range is lower, we favor
* higher numbers of salt. */ * higher numbers of salt. */
ret = (long) (max + 1 - drand); ret = (long) (max + 1 - drand);
@ -354,10 +358,9 @@ static /*@observer@*/const char *gensalt (size_t salt_size)
assert (salt_size >= MIN_SALT_SIZE && assert (salt_size >= MIN_SALT_SIZE &&
salt_size <= MAX_SALT_SIZE); salt_size <= MAX_SALT_SIZE);
seedRNG (); strcat (salt, l64a (read_random_bytes ()));
strcat (salt, l64a (random()));
do { do {
strcat (salt, l64a (random())); strcat (salt, l64a (read_random_bytes ()));
} while (strlen (salt) < salt_size); } while (strlen (salt) < salt_size);
salt[salt_size] = '\0'; salt[salt_size] = '\0';