X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Frand%2Frandfile.c;h=d024f69fe64ac56b562faf6a8b9e9e199d7a4a13;hp=19cce2c7a83674732d874486ba7bdd9ffdb3fed1;hb=4871fa49cdd0d4473b6a815fc01fbde3e6ced339;hpb=13c03c8d6da334bb1cde6ce4133e7c75b3b76947 diff --git a/crypto/rand/randfile.c b/crypto/rand/randfile.c index 19cce2c7a8..d024f69fe6 100644 --- a/crypto/rand/randfile.c +++ b/crypto/rand/randfile.c @@ -7,7 +7,7 @@ * https://www.openssl.org/source/license.html */ -#include "e_os.h" +#include "internal/cryptlib.h" #include #include @@ -21,12 +21,12 @@ #ifdef OPENSSL_SYS_VMS # include #endif -#ifndef NO_SYS_TYPES_H -# include -#endif +#include #ifndef OPENSSL_NO_POSIX_IO # include # include +#endif + /* * Following should not be needed, and we could have been stricter * and demand S_IS*. But some systems just don't comply... Formally @@ -34,23 +34,9 @@ * would look like ((m) & MASK == TYPE), but since MASK availability * is as questionable, we settle for this poor-man fallback... */ -# if !defined(S_ISBLK) -# if defined(_S_IFBLK) -# 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 +# if !defined(S_ISREG) +# define S_ISREG(m) ((m) & S_IFREG) # 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 # define stat _stat @@ -59,155 +45,97 @@ # define fdopen _fdopen #endif -#undef BUFSIZE -#define BUFSIZE 1024 -#define RAND_DATA 1024 +#define RAND_FILE_SIZE 1024 +#define RFILE ".rnd" #ifdef OPENSSL_SYS_VMS /* - * Misc hacks needed for specific cases. - * * __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 - * 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 -# pragma pointer_size save -# pragma pointer_size 32 -# endif -typedef char *char_ptr32; -# if __INITIAL_POINTER_SIZE == 64 -# pragma pointer_size restore -# endif - -/* - * 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... - */ -static void vms_setbuf(FILE *fp, char *buf) -{ - setbuf((__FILE_ptr32)fp, (char_ptr32)buf); -} -/* + * stdio functions return this type (a study of stdio.h proves it). + * * This declaration is a nasty hack to get around vms' extension to fopen for * passing in sharing options being disabled by /STANDARD=ANSI89 */ static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) = - (__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 fopen(fname,mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS) -# define setbuf(fp,buf) vms_setbuf((fp), (buf)) + (__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 openssl_fopen(fname, mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS) #endif -#define RFILE ".rnd" - /* * 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) { - /*- - * If bytes >= 0, read up to 'bytes' bytes. - * if bytes == -1, read complete file. - */ - - unsigned char buf[BUFSIZE]; + unsigned char buf[RAND_FILE_SIZE]; #ifndef OPENSSL_NO_POSIX_IO struct stat sb; #endif - int i, ret = 0, n; + int i, n, ret = 0; FILE *in; - if (file == NULL) - return (0); - -#ifndef OPENSSL_NO_POSIX_IO - /* - * struct stat can have padding and unused fields that may not be - * initialized in the call to stat(). We need to clear the entire - * structure before calling RAND_add() to avoid complaints from - * applications such as Valgrind. - */ - memset(&sb, 0, sizeof(sb)); - if (stat(file, &sb) < 0) - return (0); - RAND_add(&sb, sizeof(sb), 0.0); -#endif if (bytes == 0) - return (ret); + return 0; - in = fopen(file, "rb"); - if (in == NULL) - goto err; -#if defined(S_ISBLK) && defined(S_ISCHR) && !defined(OPENSSL_NO_POSIX_IO) - if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { - /* - * this file is a device. we don't want read an infinite number of - * bytes from a random device, nor do we want to use buffered I/O - * because we will waste system entropy. - */ - bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */ - setbuf(in, NULL); /* don't do buffered reads */ +#ifndef OPENSSL_NO_POSIX_IO + if (stat(file, &sb) < 0 || !S_ISREG(sb.st_mode)) { + RANDerr(RAND_F_RAND_LOAD_FILE, RAND_R_NOT_A_REGULAR_FILE); + ERR_add_error_data(2, "Filename=", file); + return -1; } #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) - n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE; + n = (bytes < RAND_FILE_SIZE) ? (int)bytes : RAND_FILE_SIZE; else - n = BUFSIZE; + n = RAND_FILE_SIZE; i = fread(buf, 1, n, in); if (i <= 0) break; - RAND_add(buf, i, (double)i); ret += i; - if (bytes > 0) { - bytes -= n; - if (bytes <= 0) - break; - } + + /* If given a bytecount, and we did it, break. */ + if (bytes > 0 && (bytes -= i) <= 0) + break; } + + OPENSSL_cleanse(buf, sizeof(buf)); fclose(in); - OPENSSL_cleanse(buf, BUFSIZE); - err: - return (ret); + return ret; } int RAND_write_file(const char *file) { - unsigned char buf[BUFSIZE]; - int i, ret = 0, rand_err = 0; + unsigned char buf[RAND_FILE_SIZE]; + int ret = -1; FILE *out = NULL; - int n; #ifndef OPENSSL_NO_POSIX_IO struct stat sb; - i = stat(file, &sb); - if (i != -1) { -# if defined(S_ISBLK) && defined(S_ISCHR) - if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { - /* - * this file is a device. we don't write back to it. we - * "succeed" on the assumption this is some sort of random - * device. Otherwise attempting to write to and chmod the device - * causes problems. - */ - return (1); - } -# endif + if (stat(file, &sb) >= 0 && !S_ISREG(sb.st_mode)) { + RANDerr(RAND_F_RAND_WRITE_FILE, RAND_R_NOT_A_REGULAR_FILE); + ERR_add_error_data(2, "Filename=", file); + return -1; } #endif -#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS) + /* Collect enough random data. */ + if (RAND_bytes(buf, (int)sizeof(buf)) != 1) + return -1; + +#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && \ + !defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_WINDOWS) { # ifndef O_BINARY # define O_BINARY 0 @@ -240,100 +168,93 @@ int RAND_write_file(const char *file) * application level. Also consider whether or not you NEED a persistent * rand file in a concurrent use situation. */ - - out = fopen(file, "rb+"); + out = openssl_fopen(file, "rb+"); #endif + if (out == NULL) - out = fopen(file, "wb"); - if (out == NULL) - goto err; + out = openssl_fopen(file, "wb"); + if (out == NULL) { + RANDerr(RAND_F_RAND_WRITE_FILE, RAND_R_CANNOT_OPEN_FILE); + ERR_add_error_data(2, "Filename=", file); + return -1; + } #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); #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); - OPENSSL_cleanse(buf, BUFSIZE); - err: - return (rand_err ? -1 : ret); + OPENSSL_cleanse(buf, RAND_FILE_SIZE); + return ret; } const char *RAND_file_name(char *buf, size_t size) { char *s = NULL; -#ifdef __OpenBSD__ - struct stat sb; -#endif + size_t len; + int use_randfile = 1; - if (OPENSSL_issetugid() == 0) - s = getenv("RANDFILE"); - if (s != NULL && *s && strlen(s) + 1 < size) { - if (OPENSSL_strlcpy(buf, s, size) >= size) - return NULL; - } else { -#ifdef OPENSSL_SYS_WINDOWS - /* - * We use the same env variables as GetTempFile() - but that function - * uses TCHARs, but getenv() gives us chars so its easier to do it this - * way - */ - if ((s = getenv("TMP")) == NULL - && (s = getenv("TEMP")) == NULL - && (s = getenv("USERPROFILE")) == NULL - && (s = getenv("SYSTEMROOT")) == NULL) { - s = getenv("HOME"); +#if defined(_WIN32) && defined(CP_UTF8) + DWORD envlen; + WCHAR *var; + + /* Look up various environment variables. */ + if ((envlen = GetEnvironmentVariableW(var = L"RANDFILE", NULL, 0)) == 0) { + use_randfile = 0; + if ((envlen = GetEnvironmentVariableW(var = L"HOME", NULL, 0)) == 0 + && (envlen = GetEnvironmentVariableW(var = L"USERPROFILE", + NULL, 0)) == 0) + envlen = GetEnvironmentVariableW(var = L"SYSTEMROOT", NULL, 0); + } + + /* If we got a value, allocate space to hold it and then get it. */ + if (envlen != 0) { + int sz; + WCHAR *val = _alloca(envlen * sizeof(WCHAR)); + + if (GetEnvironmentVariableW(var, val, envlen) < envlen + && (sz = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, + NULL, NULL)) != 0) { + s = _alloca(sz); + if (WideCharToMultiByte(CP_UTF8, 0, val, -1, s, sz, + NULL, NULL) == 0) + s = NULL; } + } #else - if (OPENSSL_issetugid() == 0) - s = getenv("HOME"); + if (OPENSSL_issetugid() != 0) { + use_randfile = 0; + } else if ((s = getenv("RANDFILE")) == NULL || *s == '\0') { + use_randfile = 0; + s = getenv("HOME"); + } #endif + #ifdef DEFAULT_HOME - if (s == NULL) { - s = DEFAULT_HOME; - } + if (!use_randfile && s == NULL) + s = DEFAULT_HOME; #endif - if (s && *s && strlen(s) + strlen(RFILE) + 2 < size) { - OPENSSL_strlcpy(buf, s, size); + if (s == NULL || *s == '\0') + return NULL; + + len = strlen(s); + if (use_randfile) { + if (len + 1 >= size) + return NULL; + strcpy(buf, s); + } else { + if (len + 1 + strlen(RFILE) + 1 >= size) + return NULL; + strcpy(buf, s); #ifndef OPENSSL_SYS_VMS - OPENSSL_strlcat(buf, "/", size); + strcat(buf, "/"); #endif - OPENSSL_strlcat(buf, RFILE, size); - } else - buf[0] = '\0'; /* no file name */ + strcat(buf, RFILE); } -#ifdef __OpenBSD__ - /* - * given that all random loads just fail if the file can't be seen on a - * stat, we stat the file we're returning, if it fails, use /dev/arandom - * instead. this allows the user to use their own source for good random - * data, but defaults to something hopefully decent if that isn't - * available. - */ - - if (!buf[0]) - if (OPENSSL_strlcpy(buf, "/dev/arandom", size) >= size) { - return (NULL); - } - if (stat(buf, &sb) == -1) - if (OPENSSL_strlcpy(buf, "/dev/arandom", size) >= size) { - return (NULL); - } -#endif - return (buf); + return buf; }