randfile.c revision 296465
155714Skris/* crypto/rand/randfile.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8296465Sdelphij * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15296465Sdelphij * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22296465Sdelphij * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40296465Sdelphij * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52296465Sdelphij * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 59127128Snectar/* We need to define this to get macros like S_IFBLK and S_IFCHR */ 60160814Ssimon#define _XOPEN_SOURCE 500 61127128Snectar 6255714Skris#include <errno.h> 6355714Skris#include <stdio.h> 6455714Skris#include <stdlib.h> 6555714Skris#include <string.h> 6655714Skris 67109998Smarkm#include "e_os.h" 68109998Smarkm#include <openssl/crypto.h> 69109998Smarkm#include <openssl/rand.h> 70127128Snectar#include <openssl/buffer.h> 71109998Smarkm 72109998Smarkm#ifdef OPENSSL_SYS_VMS 73296465Sdelphij# include <unixio.h> 7459191Skris#endif 7559191Skris#ifndef NO_SYS_TYPES_H 7659191Skris# include <sys/types.h> 7759191Skris#endif 7859191Skris#ifdef MAC_OS_pre_X 7959191Skris# include <stat.h> 8059191Skris#else 8159191Skris# include <sys/stat.h> 8259191Skris#endif 8359191Skris 84194206Ssimon#ifdef _WIN32 85296465Sdelphij# define stat _stat 86296465Sdelphij# define chmod _chmod 87296465Sdelphij# define open _open 88296465Sdelphij# define fdopen _fdopen 89194206Ssimon#endif 90194206Ssimon 9155714Skris#undef BUFSIZE 92296465Sdelphij#define BUFSIZE 1024 9355714Skris#define RAND_DATA 1024 9455714Skris 95194206Ssimon#ifdef OPENSSL_SYS_VMS 96296465Sdelphij/* 97296465Sdelphij * This declaration is a nasty hack to get around vms' extension to fopen for 98296465Sdelphij * passing in sharing options being disabled by our /STANDARD=ANSI89 99296465Sdelphij */ 100194206Ssimonstatic FILE *(*const vms_fopen)(const char *, const char *, ...) = 101194206Ssimon (FILE *(*)(const char *, const char *, ...))fopen; 102296465Sdelphij# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0" 103194206Ssimon#endif 104194206Ssimon 10559191Skris/* #define RFILE ".rnd" - defined in ../../e_os.h */ 10655714Skris 107296465Sdelphij/* 108296465Sdelphij * Note that these functions are intended for seed files only. Entropy 109296465Sdelphij * devices and EGD sockets are handled in rand_unix.c 110296465Sdelphij */ 11172613Skris 11255714Skrisint RAND_load_file(const char *file, long bytes) 113296465Sdelphij{ 114296465Sdelphij /*- 115296465Sdelphij * If bytes >= 0, read up to 'bytes' bytes. 116296465Sdelphij * if bytes == -1, read complete file. 117296465Sdelphij */ 11859191Skris 119296465Sdelphij MS_STATIC unsigned char buf[BUFSIZE]; 120296465Sdelphij struct stat sb; 121296465Sdelphij int i, ret = 0, n; 122296465Sdelphij FILE *in; 12355714Skris 124296465Sdelphij if (file == NULL) 125296465Sdelphij return (0); 12655714Skris 127205128Ssimon#ifdef PURIFY 128296465Sdelphij /* 129296465Sdelphij * struct stat can have padding and unused fields that may not be 130296465Sdelphij * initialized in the call to stat(). We need to clear the entire 131296465Sdelphij * structure before calling RAND_add() to avoid complaints from 132296465Sdelphij * applications such as Valgrind. 133296465Sdelphij */ 134296465Sdelphij memset(&sb, 0, sizeof(sb)); 135205128Ssimon#endif 136205128Ssimon 137296465Sdelphij if (stat(file, &sb) < 0) 138296465Sdelphij return (0); 139296465Sdelphij RAND_add(&sb, sizeof(sb), 0.0); 140296465Sdelphij if (bytes == 0) 141296465Sdelphij return (ret); 14255714Skris 143194206Ssimon#ifdef OPENSSL_SYS_VMS 144296465Sdelphij in = vms_fopen(file, "rb", VMS_OPEN_ATTRS); 145194206Ssimon#else 146296465Sdelphij in = fopen(file, "rb"); 147194206Ssimon#endif 148296465Sdelphij if (in == NULL) 149296465Sdelphij goto err; 150205128Ssimon#if defined(S_ISBLK) && defined(S_ISCHR) 151296465Sdelphij if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { 152296465Sdelphij /* 153296465Sdelphij * this file is a device. we don't want read an infinite number of 154296465Sdelphij * bytes from a random device, nor do we want to use buffered I/O 155296465Sdelphij * because we will waste system entropy. 156296465Sdelphij */ 157296465Sdelphij bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */ 158296465Sdelphij setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */ 159296465Sdelphij } 160127128Snectar#endif 161296465Sdelphij for (;;) { 162296465Sdelphij if (bytes > 0) 163296465Sdelphij n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE; 164296465Sdelphij else 165296465Sdelphij n = BUFSIZE; 166296465Sdelphij i = fread(buf, 1, n, in); 167296465Sdelphij if (i <= 0) 168296465Sdelphij break; 169194206Ssimon#ifdef PURIFY 170296465Sdelphij RAND_add(buf, i, (double)i); 171194206Ssimon#else 172296465Sdelphij /* even if n != i, use the full array */ 173296465Sdelphij RAND_add(buf, n, (double)i); 174194206Ssimon#endif 175296465Sdelphij ret += i; 176296465Sdelphij if (bytes > 0) { 177296465Sdelphij bytes -= n; 178296465Sdelphij if (bytes <= 0) 179296465Sdelphij break; 180296465Sdelphij } 181296465Sdelphij } 182296465Sdelphij fclose(in); 183296465Sdelphij OPENSSL_cleanse(buf, BUFSIZE); 184296465Sdelphij err: 185296465Sdelphij return (ret); 186296465Sdelphij} 18755714Skris 18855714Skrisint RAND_write_file(const char *file) 189296465Sdelphij{ 190296465Sdelphij unsigned char buf[BUFSIZE]; 191296465Sdelphij int i, ret = 0, rand_err = 0; 192296465Sdelphij FILE *out = NULL; 193296465Sdelphij int n; 194296465Sdelphij struct stat sb; 195296465Sdelphij 196296465Sdelphij i = stat(file, &sb); 197296465Sdelphij if (i != -1) { 198205128Ssimon#if defined(S_ISBLK) && defined(S_ISCHR) 199296465Sdelphij if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { 200296465Sdelphij /* 201296465Sdelphij * this file is a device. we don't write back to it. we 202296465Sdelphij * "succeed" on the assumption this is some sort of random 203296465Sdelphij * device. Otherwise attempting to write to and chmod the device 204296465Sdelphij * causes problems. 205296465Sdelphij */ 206296465Sdelphij return (1); 207296465Sdelphij } 208127128Snectar#endif 209296465Sdelphij } 210296465Sdelphij#if defined(O_CREAT) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_VMS) 211296465Sdelphij { 212296465Sdelphij /* For some reason Win32 can't write to files created this way */ 213127128Snectar 214296465Sdelphij /* 215296465Sdelphij * chmod(..., 0600) is too late to protect the file, permissions 216296465Sdelphij * should be restrictive from the start 217296465Sdelphij */ 218296465Sdelphij int fd = open(file, O_CREAT, 0600); 219296465Sdelphij if (fd != -1) 220296465Sdelphij out = fdopen(fd, "wb"); 221296465Sdelphij } 22259191Skris#endif 223194206Ssimon 224194206Ssimon#ifdef OPENSSL_SYS_VMS 225296465Sdelphij /* 226296465Sdelphij * VMS NOTE: Prior versions of this routine created a _new_ version of 227296465Sdelphij * the rand file for each call into this routine, then deleted all 228296465Sdelphij * existing versions named ;-1, and finally renamed the current version 229296465Sdelphij * as ';1'. Under concurrent usage, this resulted in an RMS race 230296465Sdelphij * condition in rename() which could orphan files (see vms message help 231296465Sdelphij * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares 232296465Sdelphij * the top-level version of the rand file. Note that there may still be 233296465Sdelphij * conditions where the top-level rand file is locked. If so, this code 234296465Sdelphij * will then create a new version of the rand file. Without the delete 235296465Sdelphij * and rename code, this can result in ascending file versions that stop 236296465Sdelphij * at version 32767, and this routine will then return an error. The 237296465Sdelphij * remedy for this is to recode the calling application to avoid 238296465Sdelphij * concurrent use of the rand file, or synchronize usage at the 239296465Sdelphij * application level. Also consider whether or not you NEED a persistent 240296465Sdelphij * rand file in a concurrent use situation. 241296465Sdelphij */ 242194206Ssimon 243296465Sdelphij out = vms_fopen(file, "rb+", VMS_OPEN_ATTRS); 244296465Sdelphij if (out == NULL) 245296465Sdelphij out = vms_fopen(file, "wb", VMS_OPEN_ATTRS); 246194206Ssimon#else 247296465Sdelphij if (out == NULL) 248296465Sdelphij out = fopen(file, "wb"); 249194206Ssimon#endif 250296465Sdelphij if (out == NULL) 251296465Sdelphij goto err; 25259191Skris 25359191Skris#ifndef NO_CHMOD 254296465Sdelphij chmod(file, 0600); 25559191Skris#endif 256296465Sdelphij n = RAND_DATA; 257296465Sdelphij for (;;) { 258296465Sdelphij i = (n > BUFSIZE) ? BUFSIZE : n; 259296465Sdelphij n -= BUFSIZE; 260296465Sdelphij if (RAND_bytes(buf, i) <= 0) 261296465Sdelphij rand_err = 1; 262296465Sdelphij i = fwrite(buf, 1, i, out); 263296465Sdelphij if (i <= 0) { 264296465Sdelphij ret = 0; 265296465Sdelphij break; 266296465Sdelphij } 267296465Sdelphij ret += i; 268296465Sdelphij if (n <= 0) 269296465Sdelphij break; 270296465Sdelphij } 27159191Skris 272296465Sdelphij fclose(out); 273296465Sdelphij OPENSSL_cleanse(buf, BUFSIZE); 274296465Sdelphij err: 275296465Sdelphij return (rand_err ? -1 : ret); 276296465Sdelphij} 27755714Skris 27876866Skrisconst char *RAND_file_name(char *buf, size_t size) 279296465Sdelphij{ 280296465Sdelphij char *s = NULL; 281215697Ssimon#ifdef __OpenBSD__ 282296465Sdelphij int ok = 0; 283296465Sdelphij struct stat sb; 284127128Snectar#endif 28555714Skris 286296465Sdelphij if (OPENSSL_issetugid() == 0) 287296465Sdelphij s = getenv("RANDFILE"); 288296465Sdelphij if (s != NULL && *s && strlen(s) + 1 < size) { 289296465Sdelphij if (BUF_strlcpy(buf, s, size) >= size) 290296465Sdelphij return NULL; 291296465Sdelphij } else { 292296465Sdelphij if (OPENSSL_issetugid() == 0) 293296465Sdelphij s = getenv("HOME"); 29479998Skris#ifdef DEFAULT_HOME 295296465Sdelphij if (s == NULL) { 296296465Sdelphij s = DEFAULT_HOME; 297296465Sdelphij } 29879998Skris#endif 299296465Sdelphij if (s && *s && strlen(s) + strlen(RFILE) + 2 < size) { 300296465Sdelphij BUF_strlcpy(buf, s, size); 301109998Smarkm#ifndef OPENSSL_SYS_VMS 302296465Sdelphij BUF_strlcat(buf, "/", size); 30355714Skris#endif 304296465Sdelphij BUF_strlcat(buf, RFILE, size); 305215697Ssimon#ifdef __OpenBSD__ 306296465Sdelphij ok = 1; 307215697Ssimon#endif 308296465Sdelphij } else 309296465Sdelphij buf[0] = '\0'; /* no file name */ 310296465Sdelphij } 311127128Snectar 312127128Snectar#ifdef __OpenBSD__ 313296465Sdelphij /* 314296465Sdelphij * given that all random loads just fail if the file can't be seen on a 315296465Sdelphij * stat, we stat the file we're returning, if it fails, use /dev/arandom 316296465Sdelphij * instead. this allows the user to use their own source for good random 317296465Sdelphij * data, but defaults to something hopefully decent if that isn't 318296465Sdelphij * available. 319296465Sdelphij */ 320127128Snectar 321296465Sdelphij if (!ok) 322296465Sdelphij if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) { 323296465Sdelphij return (NULL); 324296465Sdelphij } 325296465Sdelphij if (stat(buf, &sb) == -1) 326296465Sdelphij if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) { 327296465Sdelphij return (NULL); 328296465Sdelphij } 329127128Snectar#endif 330296465Sdelphij return (buf); 331296465Sdelphij} 332