Cleanup RAND_load_file,RAND_write_file

Document an internal assumption that these are only for use with files,
and return an error if not. That made the code much simpler.
Leave it as writing 1024 bytes, even though we don't need more than 256
from a security perspective.  But the amount isn't specified, now, so we
can change it later if we want.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3864)
This commit is contained in:
Rich Salz 2017-07-05 16:08:19 -04:00
parent 60eba30f60
commit 9ee344f5cd
5 changed files with 129 additions and 161 deletions

View file

@ -861,6 +861,8 @@ PKCS7_F_PKCS7_SIGN_ADD_SIGNER:137:PKCS7_sign_add_signer
PKCS7_F_PKCS7_SIMPLE_SMIMECAP:119:PKCS7_simple_smimecap PKCS7_F_PKCS7_SIMPLE_SMIMECAP:119:PKCS7_simple_smimecap
PKCS7_F_PKCS7_VERIFY:117:PKCS7_verify PKCS7_F_PKCS7_VERIFY:117:PKCS7_verify
RAND_F_RAND_BYTES:100:RAND_bytes RAND_F_RAND_BYTES:100:RAND_bytes
RAND_F_RAND_LOAD_FILE:101:RAND_load_file
RAND_F_RAND_WRITE_FILE:102:RAND_write_file
RSA_F_CHECK_PADDING_MD:140:check_padding_md RSA_F_CHECK_PADDING_MD:140:check_padding_md
RSA_F_ENCODE_PKCS1:146:encode_pkcs1 RSA_F_ENCODE_PKCS1:146:encode_pkcs1
RSA_F_INT_RSA_VERIFY:145:int_rsa_verify RSA_F_INT_RSA_VERIFY:145:int_rsa_verify
@ -2096,7 +2098,10 @@ PKCS7_R_UNSUPPORTED_CIPHER_TYPE:111:unsupported cipher type
PKCS7_R_UNSUPPORTED_CONTENT_TYPE:112:unsupported content type PKCS7_R_UNSUPPORTED_CONTENT_TYPE:112:unsupported content type
PKCS7_R_WRONG_CONTENT_TYPE:113:wrong content type PKCS7_R_WRONG_CONTENT_TYPE:113:wrong content type
PKCS7_R_WRONG_PKCS7_TYPE:114:wrong pkcs7 type PKCS7_R_WRONG_PKCS7_TYPE:114:wrong pkcs7 type
RAND_R_CANNOT_OPEN_FILE:102:Cannot open file
RAND_R_FUNC_NOT_IMPLEMENTED:101:Function not implemented RAND_R_FUNC_NOT_IMPLEMENTED:101:Function not implemented
RAND_R_FWRITE_ERROR:103:Error writing file
RAND_R_NOT_A_REGULAR_FILE:104:Not a regular file
RAND_R_PRNG_NOT_SEEDED:100:PRNG not seeded RAND_R_PRNG_NOT_SEEDED:100:PRNG not seeded
RSA_R_ALGORITHM_MISMATCH:100:algorithm mismatch RSA_R_ALGORITHM_MISMATCH:100:algorithm mismatch
RSA_R_BAD_E_VALUE:101:bad e value RSA_R_BAD_E_VALUE:101:bad e value

View file

@ -15,12 +15,18 @@
static const ERR_STRING_DATA RAND_str_functs[] = { static const ERR_STRING_DATA RAND_str_functs[] = {
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_BYTES, 0), "RAND_bytes"}, {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_BYTES, 0), "RAND_bytes"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_LOAD_FILE, 0), "RAND_load_file"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_WRITE_FILE, 0), "RAND_write_file"},
{0, NULL} {0, NULL}
}; };
static const ERR_STRING_DATA RAND_str_reasons[] = { static const ERR_STRING_DATA RAND_str_reasons[] = {
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_CANNOT_OPEN_FILE), "Cannot open file"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FUNC_NOT_IMPLEMENTED), {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FUNC_NOT_IMPLEMENTED),
"Function not implemented"}, "Function not implemented"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FWRITE_ERROR), "Error writing file"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_NOT_A_REGULAR_FILE),
"Not a regular file"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PRNG_NOT_SEEDED), "PRNG not seeded"}, {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PRNG_NOT_SEEDED), "PRNG not seeded"},
{0, NULL} {0, NULL}
}; };

View file

@ -27,6 +27,8 @@
#ifndef OPENSSL_NO_POSIX_IO #ifndef OPENSSL_NO_POSIX_IO
# include <sys/stat.h> # include <sys/stat.h>
# include <fcntl.h> # include <fcntl.h>
#endif
/* /*
* Following should not be needed, and we could have been stricter * Following should not be needed, and we could have been stricter
* and demand S_IS*. But some systems just don't comply... Formally * and demand S_IS*. But some systems just don't comply... Formally
@ -34,36 +36,18 @@
* would look like ((m) & MASK == TYPE), but since MASK availability * would look like ((m) & MASK == TYPE), but since MASK availability
* is as questionable, we settle for this poor-man fallback... * is as questionable, we settle for this poor-man fallback...
*/ */
# if !defined(S_ISBLK) # if !defined(S_ISREG)
# if defined(_S_IFBLK) # define S_ISREG(m) ((m) & S_IFREG)
# define S_ISBLK(m) ((m) & _S_IFBLK)
# elif defined(S_IFBLK)
# define S_ISBLK(m) ((m) & S_IFBLK)
# elif defined(_WIN32)
# define S_ISBLK(m) 0 /* no concept of block devices on Windows */
# endif
# endif # endif
# if !defined(S_ISCHR)
# if defined(_S_IFCHR)
# define S_ISCHR(m) ((m) & _S_IFCHR)
# elif defined(S_IFCHR)
# define S_ISCHR(m) ((m) & S_IFCHR)
# endif
# endif
#endif
#ifdef _WIN32 #ifdef _WIN32
# define stat _stat # define stat _stat
# define chmod _chmod # define chmod _chmod
# define open _open # define open _open
# define fdopen _fdopen # define fdopen _fdopen
# define fstat _fstat
# define fileno _fileno
#endif #endif
#undef BUFSIZE #define RAND_FILE_SIZE 1024
#define BUFSIZE 1024
#define RAND_DATA 1024
#ifdef OPENSSL_SYS_VMS #ifdef OPENSSL_SYS_VMS
/* /*
@ -72,23 +56,12 @@
* __FILE_ptr32 is a type provided by DEC C headers (types.h specifically) * __FILE_ptr32 is a type provided by DEC C headers (types.h specifically)
* to make sure the FILE* is a 32-bit pointer no matter what. We know that * to make sure the FILE* is a 32-bit pointer no matter what. We know that
* stdio function return this type (a study of stdio.h proves it). * stdio function return this type (a study of stdio.h proves it).
* Additionally, we create a similar char pointer type for the sake of
* vms_setbuf below.
*/ */
# if __INITIAL_POINTER_SIZE == 64 # if __INITIAL_POINTER_SIZE == 64
# pragma pointer_size save # pragma pointer_size save
# pragma pointer_size 32 # pragma pointer_size 32
typedef char *char_ptr32; typedef char *char_ptr32;
# pragma pointer_size restore # pragma pointer_size restore
/*
* On VMS, setbuf() will only take 32-bit pointers, and a compilation
* with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here.
* Since we know that the FILE* really is a 32-bit pointer expanded to
* 64 bits, we also know it's safe to convert it back to a 32-bit pointer.
* As for the buffer parameter, we only use NULL here, so that passes as
* well...
*/
# define setbuf(fp,buf) (setbuf)((__FILE_ptr32)(fp), (char_ptr32)(buf))
# endif # endif
/* /*
@ -96,8 +69,9 @@ typedef char *char_ptr32;
* passing in sharing options being disabled by /STANDARD=ANSI89 * passing in sharing options being disabled by /STANDARD=ANSI89
*/ */
static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) = static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) =
(__FILE_ptr32 (*)(const char *, const char *, ...))fopen; (__FILE_ptr32 (*)(const char *, const char *, ...))fopen;
# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0" # define VMS_OPEN_ATTRS \
"shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
# define openssl_fopen(fname,mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS) # define openssl_fopen(fname,mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS)
#endif #endif
@ -106,88 +80,74 @@ static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) =
/* /*
* Note that these functions are intended for seed files only. Entropy * Note that these functions are intended for seed files only. Entropy
* devices and EGD sockets are handled in rand_unix.c * devices and EGD sockets are handled in rand_unix.c If |bytes| is
* -1 read the complete file; otherwise read the specified amount.
*/ */
int RAND_load_file(const char *file, long bytes) int RAND_load_file(const char *file, long bytes)
{ {
/*- unsigned char buf[RAND_FILE_SIZE];
* If bytes >= 0, read up to 'bytes' bytes.
* if bytes == -1, read complete file.
*/
unsigned char buf[BUFSIZE];
#ifndef OPENSSL_NO_POSIX_IO #ifndef OPENSSL_NO_POSIX_IO
struct stat sb; struct stat sb;
#endif #endif
int i, ret = 0, n; int i, n, ret = 0;
FILE *in = NULL; FILE *in;
if (file == NULL)
return 0;
if (bytes == 0) if (bytes == 0)
return ret; return 0;
in = openssl_fopen(file, "rb");
if (in == NULL)
goto err;
#ifndef OPENSSL_NO_POSIX_IO #ifndef OPENSSL_NO_POSIX_IO
/* if (stat(file, &sb) < 0 || !S_ISREG(sb.st_mode)) {
* struct stat can have padding and unused fields that may not be RANDerr(RAND_F_RAND_LOAD_FILE, RAND_R_NOT_A_REGULAR_FILE);
* initialized in the call to stat(). We need to clear the entire ERR_add_error_data(2, "Filename=", file);
* structure before calling RAND_add() to avoid complaints from return -1;
* applications such as Valgrind. }
*/
memset(&sb, 0, sizeof(sb));
if (fstat(fileno(in), &sb) < 0)
goto err;
RAND_add(&sb, sizeof(sb), 0.0);
#endif #endif
for (;;) { if ((in = openssl_fopen(file, "rb")) == NULL) {
RANDerr(RAND_F_RAND_LOAD_FILE, RAND_R_CANNOT_OPEN_FILE);
ERR_add_error_data(2, "Filename=", file);
return -1;
}
for ( ; ; ) {
if (bytes > 0) if (bytes > 0)
n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE; n = (bytes < RAND_FILE_SIZE) ? (int)bytes : RAND_FILE_SIZE;
else else
n = BUFSIZE; n = RAND_FILE_SIZE;
i = fread(buf, 1, n, in); i = fread(buf, 1, n, in);
if (i <= 0) if (i <= 0)
break; break;
RAND_add(buf, i, (double)i); RAND_add(buf, i, (double)i);
ret += i; ret += i;
if (bytes > 0) {
bytes -= n; /* If given a bytecount, and we did it, break. */
if (bytes <= 0) if (bytes > 0 && (bytes -= i) <= 0)
break; break;
}
} }
OPENSSL_cleanse(buf, BUFSIZE);
err: OPENSSL_cleanse(buf, sizeof(buf));
if (in != NULL) fclose(in);
fclose(in);
return ret; return ret;
} }
int RAND_write_file(const char *file) int RAND_write_file(const char *file)
{ {
unsigned char buf[BUFSIZE]; unsigned char buf[RAND_FILE_SIZE];
int i, ret = 0, rand_err = 0; int ret = -1;
FILE *out = NULL; FILE *out = NULL;
int n;
#ifndef OPENSSL_NO_POSIX_IO #ifndef OPENSSL_NO_POSIX_IO
struct stat sb;
# if defined(S_ISBLK) && defined(S_ISCHR) if (stat(file, &sb) >= 0 && !S_ISREG(sb.st_mode)) {
# ifdef _WIN32 RANDerr(RAND_F_RAND_WRITE_FILE, RAND_R_NOT_A_REGULAR_FILE);
/* ERR_add_error_data(2, "Filename=", file);
* Check for |file| being a driver as "ASCII-safe" on Windows, return -1;
* because driver paths are always ASCII. }
*/
# endif
# endif
#endif #endif
/* Collect enough random data. */
if (RAND_bytes(buf, (int)sizeof(buf)) != 1)
return -1;
#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && \ #if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && \
!defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_WINDOWS) !defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_WINDOWS)
{ {
@ -222,66 +182,54 @@ int RAND_write_file(const char *file)
* application level. Also consider whether or not you NEED a persistent * application level. Also consider whether or not you NEED a persistent
* rand file in a concurrent use situation. * rand file in a concurrent use situation.
*/ */
out = openssl_fopen(file, "rb+"); out = openssl_fopen(file, "rb+");
#endif #endif
if (out == NULL) if (out == NULL)
out = openssl_fopen(file, "wb"); out = openssl_fopen(file, "wb");
if (out == NULL) if (out == NULL)
goto err; return -1;
#if !defined(NO_CHMOD) && !defined(OPENSSL_NO_POSIX_IO) #if !defined(NO_CHMOD) && !defined(OPENSSL_NO_POSIX_IO)
/*
* Yes it's late to do this (see above comment), but better than nothing.
*/
chmod(file, 0600); chmod(file, 0600);
#endif #endif
n = RAND_DATA;
for (;;) {
i = (n > BUFSIZE) ? BUFSIZE : n;
n -= BUFSIZE;
if (RAND_bytes(buf, i) <= 0)
rand_err = 1;
i = fwrite(buf, 1, i, out);
if (i <= 0) {
ret = 0;
break;
}
ret += i;
if (n <= 0)
break;
}
ret = fwrite(buf, 1, RAND_FILE_SIZE, out);
fclose(out); fclose(out);
OPENSSL_cleanse(buf, BUFSIZE); OPENSSL_cleanse(buf, RAND_FILE_SIZE);
err: return ret;
return (rand_err ? -1 : ret);
} }
const char *RAND_file_name(char *buf, size_t size) const char *RAND_file_name(char *buf, size_t size)
{ {
char *s = NULL; char *s = NULL;
size_t len;
int use_randfile = 1; int use_randfile = 1;
#if defined(_WIN32) && defined(CP_UTF8) #if defined(_WIN32) && defined(CP_UTF8)
DWORD len; DWORD envlen;
WCHAR *var, *val; WCHAR *var;
if ((var = L"RANDFILE", /* Look up various environment variables. */
len = GetEnvironmentVariableW(var, NULL, 0)) == 0 if ((envlen = GetEnvironmentVariableW(var = L"RANDFILE", NULL, 0)) == 0) {
&& (var = L"HOME", use_randfile = 0, use_randfile = 0;
len = GetEnvironmentVariableW(var, NULL, 0)) == 0 if ((envlen = GetEnvironmentVariableW(var = L"HOME", NULL, 0)) == 0
&& (var = L"USERPROFILE", && (envlen = GetEnvironmentVariableW(var = L"USERPROFILE",
len = GetEnvironmentVariableW(var, NULL, 0)) == 0) { NULL, 0)) == 0)
var = L"SYSTEMROOT", envlen = GetEnvironmentVariableW(var = L"SYSTEMROOT", NULL, 0);
len = GetEnvironmentVariableW(var, NULL, 0);
} }
if (len != 0) { /* If we got a value, allocate space to hold it and then get it. */
if (envlen != 0) {
int sz; int sz;
WCHAR *val = _alloca(envlen * sizeof(WCHAR));
val = _alloca(len * sizeof(WCHAR)); if (GetEnvironmentVariableW(var, val, envlen) < envlen
&& (sz = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0,
if (GetEnvironmentVariableW(var, val, len) < len NULL, NULL)) != 0) {
&& (sz = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0,
NULL, NULL)) != 0) {
s = _alloca(sz); s = _alloca(sz);
if (WideCharToMultiByte(CP_UTF8, 0, val, -1, s, sz, if (WideCharToMultiByte(CP_UTF8, 0, val, -1, s, sz,
NULL, NULL) == 0) NULL, NULL) == 0)
@ -291,35 +239,33 @@ const char *RAND_file_name(char *buf, size_t size)
#else #else
if (OPENSSL_issetugid() != 0) { if (OPENSSL_issetugid() != 0) {
use_randfile = 0; use_randfile = 0;
} else { } else if ((s = getenv("RANDFILE")) == NULL || *s == '\0') {
s = getenv("RANDFILE"); use_randfile = 0;
if (s == NULL || *s == '\0') { s = getenv("HOME");
use_randfile = 0;
s = getenv("HOME");
}
} }
#endif #endif
#ifdef DEFAULT_HOME #ifdef DEFAULT_HOME
if (!use_randfile && s == NULL) { if (!use_randfile && s == NULL)
s = DEFAULT_HOME; s = DEFAULT_HOME;
}
#endif #endif
if (s != NULL && *s) { if (s == NULL || *s == '\0')
size_t len = strlen(s); return NULL;
if (use_randfile && len + 1 < size) { len = strlen(s);
if (OPENSSL_strlcpy(buf, s, size) >= size) if (use_randfile) {
return NULL; if (len + 1 >= size)
} else if (len + strlen(RFILE) + 2 < size) { return NULL;
OPENSSL_strlcpy(buf, s, size); strcpy(buf, s);
#ifndef OPENSSL_SYS_VMS
OPENSSL_strlcat(buf, "/", size);
#endif
OPENSSL_strlcat(buf, RFILE, size);
}
} else { } else {
buf[0] = '\0'; /* no file name */ if (len + 1 + strlen(RFILE) + 1 >= size)
return NULL;
strcpy(buf, s);
#ifndef OPENSSL_SYS_VMS
strcat(buf, "/");
#endif
strcat(buf, RFILE);
} }
return buf[0] ? buf : NULL; return buf;
} }

View file

@ -8,51 +8,50 @@ RAND_load_file, RAND_write_file, RAND_file_name - PRNG seed file
#include <openssl/rand.h> #include <openssl/rand.h>
const char *RAND_file_name(char *buf, size_t num);
int RAND_load_file(const char *filename, long max_bytes); int RAND_load_file(const char *filename, long max_bytes);
int RAND_write_file(const char *filename); int RAND_write_file(const char *filename);
const char *RAND_file_name(char *buf, size_t num);
=head1 DESCRIPTION =head1 DESCRIPTION
RAND_load_file() reads a number of bytes from file B<filename> and
adds them to the PRNG. If B<max_bytes> is non-negative,
up to B<max_bytes> are read;
if B<max_bytes> is -1, the complete file is read.
RAND_write_file() writes a number of random bytes (currently 256) to
file B<filename> which can be used to initialize the PRNG by calling
RAND_load_file() in a later session.
RAND_file_name() generates a default path for the random seed RAND_file_name() generates a default path for the random seed
file. B<buf> points to a buffer of size B<num> in which to store the file. B<buf> points to a buffer of size B<num> in which to store the
filename. filename.
On all systems, if the environment variable B<RANDFILE> is set, its On all systems, if the environment variable B<RANDFILE> is set, its
value will be used as the seed file name. value will be used as the seed file name.
Otherwise, the file is called C<.rnd>, found in platform dependent locations:
Otherwise, the file is called ".rnd", found in platform dependent locations:
=over 4 =over 4
=item On Windows (in order of preference) =item On Windows (in order of preference)
%HOME%, %USERPROFILE%, %SYSTEMROOT%, C:\ %HOME%, %USERPROFILE%, %SYSTEMROOT%, C:\
=item On VMS =item On VMS
SYS$LOGIN: SYS$LOGIN:
=item On all other systems =item On all other systems
$HOME $HOME
=back =back
If C<$HOME> (on non-Windows and non-VMS system) is not set either, or If C<$HOME> (on non-Windows and non-VMS system) is not set either, or
B<num> is too small for the path name, an error occurs. B<num> is too small for the path name, an error occurs.
RAND_load_file() reads a number of bytes from file B<filename> and
adds them to the PRNG. If B<max_bytes> is non-negative,
up to B<max_bytes> are read;
if B<max_bytes> is -1, the complete file is read.
RAND_write_file() writes a number of random bytes (currently 1024) to
file B<filename> which can be used to initialize the PRNG by calling
RAND_load_file() in a later session.
=head1 RETURN VALUES =head1 RETURN VALUES
RAND_load_file() returns the number of bytes read. RAND_load_file() returns the number of bytes read.
@ -67,6 +66,13 @@ error.
L<RAND_bytes(3)>, L<RAND_add(3)>, L<RAND_cleanup(3)> L<RAND_bytes(3)>, L<RAND_add(3)>, L<RAND_cleanup(3)>
=head1 HISTORY
A comment in the source since at least OpenSSL version 1.0.2 said that
RAND_load_file() and RAND_write_file() were only intended for regular files,
and not really device special files such as C</dev/random>. This was
poorly enforced before OpenSSL version 1.1.1.
=head1 COPYRIGHT =head1 COPYRIGHT
Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.

View file

@ -23,11 +23,16 @@ int ERR_load_RAND_strings(void);
* RAND function codes. * RAND function codes.
*/ */
# define RAND_F_RAND_BYTES 100 # define RAND_F_RAND_BYTES 100
# define RAND_F_RAND_LOAD_FILE 101
# define RAND_F_RAND_WRITE_FILE 102
/* /*
* RAND reason codes. * RAND reason codes.
*/ */
# define RAND_R_CANNOT_OPEN_FILE 102
# define RAND_R_FUNC_NOT_IMPLEMENTED 101 # define RAND_R_FUNC_NOT_IMPLEMENTED 101
# define RAND_R_FWRITE_ERROR 103
# define RAND_R_NOT_A_REGULAR_FILE 104
# define RAND_R_PRNG_NOT_SEEDED 100 # define RAND_R_PRNG_NOT_SEEDED 100
#endif #endif