1231990Smp/* crypto/rand/randfile.c */ 259243Sobrien/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 359243Sobrien * All rights reserved. 459243Sobrien * 559243Sobrien * This package is an SSL implementation written 659243Sobrien * by Eric Young (eay@cryptsoft.com). 759243Sobrien * The implementation was written so as to conform with Netscapes SSL. 859243Sobrien * 959243Sobrien * This library is free for commercial and non-commercial use as long as 1059243Sobrien * the following conditions are aheared to. The following conditions 1159243Sobrien * apply to all code found in this distribution, be it the RC4, RSA, 1259243Sobrien * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1359243Sobrien * included with this distribution is covered by the same copyright terms 1459243Sobrien * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1559243Sobrien * 1659243Sobrien * Copyright remains Eric Young's, and as such any Copyright notices in 17100616Smp * the code are not to be removed. 1859243Sobrien * If this package is used in a product, Eric Young should be given attribution 1959243Sobrien * as the author of the parts of the library used. 2059243Sobrien * This can be in the form of a textual message at program startup or 2159243Sobrien * in documentation (online or textual) provided with the package. 2259243Sobrien * 2359243Sobrien * Redistribution and use in source and binary forms, with or without 2459243Sobrien * modification, are permitted provided that the following conditions 2559243Sobrien * are met: 2659243Sobrien * 1. Redistributions of source code must retain the copyright 2759243Sobrien * notice, this list of conditions and the following disclaimer. 2859243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 2959243Sobrien * notice, this list of conditions and the following disclaimer in the 3059243Sobrien * documentation and/or other materials provided with the distribution. 3159243Sobrien * 3. All advertising materials mentioning features or use of this software 3259243Sobrien * must display the following acknowledgement: 3359243Sobrien * "This product includes cryptographic software written by 3459243Sobrien * Eric Young (eay@cryptsoft.com)" 35231990Smp * The word 'cryptographic' can be left out if the rouines from the library 3659243Sobrien * being used are not cryptographic related :-). 3759243Sobrien * 4. If you include any Windows specific code (or a derivative thereof) from 3859243Sobrien * the apps directory (application code) you must include an acknowledgement: 3959243Sobrien * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4059243Sobrien * 4159243Sobrien * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50231990Smp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51145479Smp * SUCH DAMAGE. 52167465Smp * 5359243Sobrien * The licence and distribution terms for any publically available version or 54145479Smp * derivative of this code cannot be changed. i.e. this code cannot simply be 5559243Sobrien * copied and put under another distribution licence 5659243Sobrien * [including the GNU Public Licence.] 5759243Sobrien */ 5859243Sobrien 5959243Sobrien/* We need to define this to get macros like S_IFBLK and S_IFCHR */ 6059243Sobrien#if !defined(OPENSSL_SYS_VXWORKS) 6159243Sobrien# define _XOPEN_SOURCE 500 6259243Sobrien#endif 6359243Sobrien 6459243Sobrien#include <errno.h> 6559243Sobrien#include <stdio.h> 6659243Sobrien#include <stdlib.h> 6759243Sobrien#include <string.h> 6859243Sobrien 69167465Smp#include "e_os.h" 70167465Smp#include <openssl/crypto.h> 71167465Smp#include <openssl/rand.h> 7259243Sobrien#include <openssl/buffer.h> 73167465Smp 74167465Smp#ifdef OPENSSL_SYS_VMS 75167465Smp# include <unixio.h> 76167465Smp#endif 77167465Smp#ifndef NO_SYS_TYPES_H 78167465Smp# include <sys/types.h> 79167465Smp#endif 80167465Smp#ifndef OPENSSL_NO_POSIX_IO 81167465Smp# include <sys/stat.h> 82167465Smp# include <fcntl.h> 83167465Smp#endif 8459243Sobrien 8559243Sobrien#ifdef _WIN32 8659243Sobrien# define stat _stat 8759243Sobrien# define chmod _chmod 8859243Sobrien# define open _open 8959243Sobrien# define fdopen _fdopen 90167465Smp#endif 9159243Sobrien 92145479Smp#undef BUFSIZE 93145479Smp#define BUFSIZE 1024 9459243Sobrien#define RAND_DATA 1024 9559243Sobrien 9659243Sobrien#ifdef OPENSSL_SYS_VMS 9759243Sobrien/* 9859243Sobrien * This declaration is a nasty hack to get around vms' extension to fopen for 9959243Sobrien * passing in sharing options being disabled by our /STANDARD=ANSI89 10059243Sobrien */ 101167465Smpstatic FILE *(*const vms_fopen)(const char *, const char *, ...) = 102167465Smp (FILE *(*)(const char *, const char *, ...))fopen; 103167465Smp# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0" 10459243Sobrien#endif 105167465Smp 10659243Sobrien/* #define RFILE ".rnd" - defined in ../../e_os.h */ 10759243Sobrien 10859243Sobrien/* 10959243Sobrien * Note that these functions are intended for seed files only. Entropy 11059243Sobrien * devices and EGD sockets are handled in rand_unix.c 11159243Sobrien */ 11259243Sobrien 11359243Sobrienint RAND_load_file(const char *file, long bytes) 11459243Sobrien{ 11559243Sobrien /*- 116167465Smp * If bytes >= 0, read up to 'bytes' bytes. 11759243Sobrien * if bytes == -1, read complete file. 118167465Smp */ 11959243Sobrien 12059243Sobrien MS_STATIC unsigned char buf[BUFSIZE]; 12159243Sobrien#ifndef OPENSSL_NO_POSIX_IO 12259243Sobrien struct stat sb; 12359243Sobrien#endif 124167465Smp int i, ret = 0, n; 125167465Smp FILE *in; 126167465Smp 12759243Sobrien if (file == NULL) 12859243Sobrien return (0); 12959243Sobrien 130167465Smp#ifndef OPENSSL_NO_POSIX_IO 131167465Smp# ifdef PURIFY 13259243Sobrien /* 13359243Sobrien * struct stat can have padding and unused fields that may not be 13459243Sobrien * initialized in the call to stat(). We need to clear the entire 13559243Sobrien * structure before calling RAND_add() to avoid complaints from 13659243Sobrien * applications such as Valgrind. 13759243Sobrien */ 138167465Smp memset(&sb, 0, sizeof(sb)); 139167465Smp# endif 14059243Sobrien if (stat(file, &sb) < 0) 141195609Smp return (0); 142195609Smp RAND_add(&sb, sizeof(sb), 0.0); 143167465Smp#endif 14459243Sobrien if (bytes == 0) 14559243Sobrien return (ret); 14659243Sobrien 14759243Sobrien#ifdef OPENSSL_SYS_VMS 14859243Sobrien in = vms_fopen(file, "rb", VMS_OPEN_ATTRS); 14959243Sobrien#else 150195609Smp in = fopen(file, "rb"); 151195609Smp#endif 15259243Sobrien if (in == NULL) 153195609Smp goto err; 154195609Smp#if defined(S_IFBLK) && defined(S_IFCHR) && !defined(OPENSSL_NO_POSIX_IO) 155195609Smp if (sb.st_mode & (S_IFBLK | S_IFCHR)) { 156195609Smp /* 157195609Smp * this file is a device. we don't want read an infinite number of 15859243Sobrien * bytes from a random device, nor do we want to use buffered I/O 15959243Sobrien * because we will waste system entropy. 16059243Sobrien */ 16159243Sobrien bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */ 16259243Sobrien# ifndef OPENSSL_NO_SETVBUF_IONBF 163167465Smp setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */ 164167465Smp# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */ 16559243Sobrien } 166145479Smp#endif 16759243Sobrien for (;;) { 16859243Sobrien if (bytes > 0) 16959243Sobrien n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE; 17059243Sobrien else 17159243Sobrien n = BUFSIZE; 17259243Sobrien i = fread(buf, 1, n, in); 17359243Sobrien if (i <= 0) 174167465Smp break; 17559243Sobrien#ifdef PURIFY 17659243Sobrien RAND_add(buf, i, (double)i); 17759243Sobrien#else 17859243Sobrien /* even if n != i, use the full array */ 17959243Sobrien RAND_add(buf, n, (double)i); 18059243Sobrien#endif 18159243Sobrien ret += i; 18259243Sobrien if (bytes > 0) { 183167465Smp bytes -= n; 18459243Sobrien if (bytes <= 0) 18559243Sobrien break; 18659243Sobrien } 18759243Sobrien } 188167465Smp fclose(in); 189167465Smp OPENSSL_cleanse(buf, BUFSIZE); 19059243Sobrien err: 191167465Smp return (ret); 19259243Sobrien} 19359243Sobrien 19459243Sobrienint RAND_write_file(const char *file) 19559243Sobrien{ 19659243Sobrien unsigned char buf[BUFSIZE]; 19759243Sobrien int i, ret = 0, rand_err = 0; 19859243Sobrien FILE *out = NULL; 19959243Sobrien int n; 20059243Sobrien#ifndef OPENSSL_NO_POSIX_IO 20159243Sobrien struct stat sb; 202167465Smp 20359243Sobrien i = stat(file, &sb); 204145479Smp if (i != -1) { 205195609Smp# if defined(S_ISBLK) && defined(S_ISCHR) 206145479Smp if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { 207167465Smp /* 208195609Smp * this file is a device. we don't write back to it. we 20959243Sobrien * "succeed" on the assumption this is some sort of random 210195609Smp * device. Otherwise attempting to write to and chmod the device 211167465Smp * causes problems. 21259243Sobrien */ 21359243Sobrien return (1); 21459243Sobrien } 21559243Sobrien# endif 216167465Smp } 217195609Smp#endif 21859243Sobrien 219167465Smp#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS) 22059243Sobrien { 22159243Sobrien# ifndef O_BINARY 22259243Sobrien# define O_BINARY 0 22359243Sobrien# endif 22459243Sobrien /* 225167465Smp * chmod(..., 0600) is too late to protect the file, permissions 22659243Sobrien * should be restrictive from the start 22759243Sobrien */ 22859243Sobrien int fd = open(file, O_WRONLY | O_CREAT | O_BINARY, 0600); 229167465Smp if (fd != -1) 23059243Sobrien out = fdopen(fd, "wb"); 23159243Sobrien } 23259243Sobrien#endif 233195609Smp 23459243Sobrien#ifdef OPENSSL_SYS_VMS 23559243Sobrien /* 23659243Sobrien * VMS NOTE: Prior versions of this routine created a _new_ version of 23759243Sobrien * the rand file for each call into this routine, then deleted all 23859243Sobrien * existing versions named ;-1, and finally renamed the current version 23959243Sobrien * as ';1'. Under concurrent usage, this resulted in an RMS race 24059243Sobrien * condition in rename() which could orphan files (see vms message help 24159243Sobrien * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares 24259243Sobrien * the top-level version of the rand file. Note that there may still be 24359243Sobrien * conditions where the top-level rand file is locked. If so, this code 24459243Sobrien * will then create a new version of the rand file. Without the delete 24559243Sobrien * and rename code, this can result in ascending file versions that stop 24659243Sobrien * at version 32767, and this routine will then return an error. The 247195609Smp * remedy for this is to recode the calling application to avoid 248195609Smp * concurrent use of the rand file, or synchronize usage at the 249145479Smp * application level. Also consider whether or not you NEED a persistent 250195609Smp * rand file in a concurrent use situation. 25159243Sobrien */ 252195609Smp 253195609Smp out = vms_fopen(file, "rb+", VMS_OPEN_ATTRS); 25459243Sobrien if (out == NULL) 25559243Sobrien out = vms_fopen(file, "wb", VMS_OPEN_ATTRS); 25659243Sobrien#else 25759243Sobrien if (out == NULL) 25859243Sobrien out = fopen(file, "wb"); 25959243Sobrien#endif 26059243Sobrien if (out == NULL) 26159243Sobrien goto err; 262195609Smp 26359243Sobrien#ifndef NO_CHMOD 26459243Sobrien chmod(file, 0600); 26559243Sobrien#endif 26659243Sobrien n = RAND_DATA; 267195609Smp for (;;) { 26859243Sobrien i = (n > BUFSIZE) ? BUFSIZE : n; 26959243Sobrien n -= BUFSIZE; 27059243Sobrien if (RAND_bytes(buf, i) <= 0) 27159243Sobrien rand_err = 1; 272195609Smp i = fwrite(buf, 1, i, out); 27359243Sobrien if (i <= 0) { 27459243Sobrien ret = 0; 27559243Sobrien break; 27659243Sobrien } 27759243Sobrien ret += i; 27859243Sobrien if (n <= 0) 27959243Sobrien break; 280195609Smp } 28159243Sobrien 282195609Smp fclose(out); 283167465Smp OPENSSL_cleanse(buf, BUFSIZE); 284167465Smp err: 28559243Sobrien return (rand_err ? -1 : ret); 28659243Sobrien} 28759243Sobrien 288167465Smpconst char *RAND_file_name(char *buf, size_t size) 289167465Smp{ 29059243Sobrien char *s = NULL; 29159243Sobrien#ifdef __OpenBSD__ 29259243Sobrien struct stat sb; 29359243Sobrien#endif 29459243Sobrien 29559243Sobrien if (OPENSSL_issetugid() == 0) 296167465Smp s = getenv("RANDFILE"); 297167465Smp if (s != NULL && *s && strlen(s) + 1 < size) { 298195609Smp if (BUF_strlcpy(buf, s, size) >= size) 299167465Smp return NULL; 30059243Sobrien } else { 301167465Smp if (OPENSSL_issetugid() == 0) 302167465Smp s = getenv("HOME"); 303195609Smp#ifdef DEFAULT_HOME 304195609Smp if (s == NULL) { 305195609Smp s = DEFAULT_HOME; 306195609Smp } 307195609Smp#endif 308167465Smp if (s && *s && strlen(s) + strlen(RFILE) + 2 < size) { 30959243Sobrien BUF_strlcpy(buf, s, size); 31059243Sobrien#ifndef OPENSSL_SYS_VMS 31159243Sobrien BUF_strlcat(buf, "/", size); 31259243Sobrien#endif 31359243Sobrien BUF_strlcat(buf, RFILE, size); 31459243Sobrien } else 31559243Sobrien buf[0] = '\0'; /* no file name */ 31659243Sobrien } 317145479Smp 318167465Smp#ifdef __OpenBSD__ 31959243Sobrien /* 320231990Smp * given that all random loads just fail if the file can't be seen on a 32159243Sobrien * stat, we stat the file we're returning, if it fails, use /dev/arandom 32259243Sobrien * instead. this allows the user to use their own source for good random 32359243Sobrien * data, but defaults to something hopefully decent if that isn't 32459243Sobrien * available. 32559243Sobrien */ 32659243Sobrien 327167465Smp if (!buf[0]) 328167465Smp if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) { 32959243Sobrien return (NULL); 33059243Sobrien } 33159243Sobrien if (stat(buf, &sb) == -1) 33259243Sobrien if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) { 33359243Sobrien return (NULL); 33459243Sobrien } 33559243Sobrien#endif 33659243Sobrien return (buf); 33759243Sobrien} 33859243Sobrien