randfile.c revision 215697
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.
855714Skris *
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).
1555714Skris *
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.
2255714Skris *
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 :-).
3755714Skris * 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)"
4055714Skris *
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.
5255714Skris *
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
7359191Skris#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
85194206Ssimon#define stat	_stat
86194206Ssimon#define chmod	_chmod
87194206Ssimon#define open	_open
88194206Ssimon#define fdopen	_fdopen
89194206Ssimon#endif
90194206Ssimon
9155714Skris#undef BUFSIZE
9255714Skris#define BUFSIZE	1024
9355714Skris#define RAND_DATA 1024
9455714Skris
95194206Ssimon#ifdef OPENSSL_SYS_VMS
96194206Ssimon/* This declaration is a nasty hack to get around vms' extension to fopen
97194206Ssimon * for passing in sharing options being disabled by our /STANDARD=ANSI89 */
98194206Ssimonstatic FILE *(*const vms_fopen)(const char *, const char *, ...) =
99194206Ssimon    (FILE *(*)(const char *, const char *, ...))fopen;
100194206Ssimon#define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
101194206Ssimon#endif
102194206Ssimon
10359191Skris/* #define RFILE ".rnd" - defined in ../../e_os.h */
10455714Skris
10572613Skris/* Note that these functions are intended for seed files only.
10672613Skris * Entropy devices and EGD sockets are handled in rand_unix.c */
10772613Skris
10855714Skrisint RAND_load_file(const char *file, long bytes)
10955714Skris	{
11059191Skris	/* If bytes >= 0, read up to 'bytes' bytes.
11159191Skris	 * if bytes == -1, read complete file. */
11259191Skris
11355714Skris	MS_STATIC unsigned char buf[BUFSIZE];
11455714Skris	struct stat sb;
11555714Skris	int i,ret=0,n;
11655714Skris	FILE *in;
11755714Skris
11855714Skris	if (file == NULL) return(0);
11955714Skris
120205128Ssimon#ifdef PURIFY
121205128Ssimon	/* struct stat can have padding and unused fields that may not be
122205128Ssimon	 * initialized in the call to stat(). We need to clear the entire
123205128Ssimon	 * structure before calling RAND_add() to avoid complaints from
124205128Ssimon	 * applications such as Valgrind.
125205128Ssimon	 */
126205128Ssimon	memset(&sb, 0, sizeof(sb));
127205128Ssimon#endif
128205128Ssimon
129194206Ssimon	if (stat(file,&sb) < 0) return(0);
130160814Ssimon	RAND_add(&sb,sizeof(sb),0.0);
13159191Skris	if (bytes == 0) return(ret);
13255714Skris
133194206Ssimon#ifdef OPENSSL_SYS_VMS
134194206Ssimon	in=vms_fopen(file,"rb",VMS_OPEN_ATTRS);
135194206Ssimon#else
13655714Skris	in=fopen(file,"rb");
137194206Ssimon#endif
13855714Skris	if (in == NULL) goto err;
139205128Ssimon#if defined(S_ISBLK) && defined(S_ISCHR)
140205128Ssimon	if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
141127128Snectar	  /* this file is a device. we don't want read an infinite number
142127128Snectar	   * of bytes from a random device, nor do we want to use buffered
143127128Snectar	   * I/O because we will waste system entropy.
144127128Snectar	   */
145127128Snectar	  bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
146127128Snectar	  setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */
147127128Snectar	}
148127128Snectar#endif
14955714Skris	for (;;)
15055714Skris		{
15159191Skris		if (bytes > 0)
15259191Skris			n = (bytes < BUFSIZE)?(int)bytes:BUFSIZE;
15359191Skris		else
15459191Skris			n = BUFSIZE;
15555714Skris		i=fread(buf,1,n,in);
15655714Skris		if (i <= 0) break;
157194206Ssimon#ifdef PURIFY
158194206Ssimon		RAND_add(buf,i,(double)i);
159194206Ssimon#else
16055714Skris		/* even if n != i, use the full array */
161160814Ssimon		RAND_add(buf,n,(double)i);
162194206Ssimon#endif
16355714Skris		ret+=i;
16459191Skris		if (bytes > 0)
16559191Skris			{
16659191Skris			bytes-=n;
16772613Skris			if (bytes <= 0) break;
16859191Skris			}
16955714Skris		}
17055714Skris	fclose(in);
171109998Smarkm	OPENSSL_cleanse(buf,BUFSIZE);
17255714Skriserr:
17355714Skris	return(ret);
17455714Skris	}
17555714Skris
17655714Skrisint RAND_write_file(const char *file)
17755714Skris	{
17855714Skris	unsigned char buf[BUFSIZE];
17968651Skris	int i,ret=0,rand_err=0;
18059191Skris	FILE *out = NULL;
18155714Skris	int n;
182127128Snectar	struct stat sb;
18359191Skris
184127128Snectar	i=stat(file,&sb);
185127128Snectar	if (i != -1) {
186205128Ssimon#if defined(S_ISBLK) && defined(S_ISCHR)
187205128Ssimon	  if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
188127128Snectar	    /* this file is a device. we don't write back to it.
189127128Snectar	     * we "succeed" on the assumption this is some sort
190127128Snectar	     * of random device. Otherwise attempting to write to
191127128Snectar	     * and chmod the device causes problems.
192127128Snectar	     */
193127128Snectar	    return(1);
194127128Snectar	  }
195127128Snectar#endif
196127128Snectar	}
197127128Snectar
198194206Ssimon#if defined(O_CREAT) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_VMS)
199142425Snectar	{
20059191Skris	/* For some reason Win32 can't write to files created this way */
20168651Skris
20268651Skris	/* chmod(..., 0600) is too late to protect the file,
20368651Skris	 * permissions should be restrictive from the start */
20468651Skris	int fd = open(file, O_CREAT, 0600);
20568651Skris	if (fd != -1)
20668651Skris		out = fdopen(fd, "wb");
207142425Snectar	}
20859191Skris#endif
209194206Ssimon
210194206Ssimon#ifdef OPENSSL_SYS_VMS
211194206Ssimon	/* VMS NOTE: Prior versions of this routine created a _new_
212194206Ssimon	 * version of the rand file for each call into this routine, then
213194206Ssimon	 * deleted all existing versions named ;-1, and finally renamed
214194206Ssimon	 * the current version as ';1'. Under concurrent usage, this
215194206Ssimon	 * resulted in an RMS race condition in rename() which could
216194206Ssimon	 * orphan files (see vms message help for RMS$_REENT). With the
217194206Ssimon	 * fopen() calls below, openssl/VMS now shares the top-level
218194206Ssimon	 * version of the rand file. Note that there may still be
219194206Ssimon	 * conditions where the top-level rand file is locked. If so, this
220194206Ssimon	 * code will then create a new version of the rand file. Without
221194206Ssimon	 * the delete and rename code, this can result in ascending file
222194206Ssimon	 * versions that stop at version 32767, and this routine will then
223194206Ssimon	 * return an error. The remedy for this is to recode the calling
224194206Ssimon	 * application to avoid concurrent use of the rand file, or
225194206Ssimon	 * synchronize usage at the application level. Also consider
226194206Ssimon	 * whether or not you NEED a persistent rand file in a concurrent
227194206Ssimon	 * use situation.
228194206Ssimon	 */
229194206Ssimon
230194206Ssimon	out = vms_fopen(file,"rb+",VMS_OPEN_ATTRS);
23168651Skris	if (out == NULL)
232194206Ssimon		out = vms_fopen(file,"wb",VMS_OPEN_ATTRS);
233194206Ssimon#else
234194206Ssimon	if (out == NULL)
23568651Skris		out = fopen(file,"wb");
236194206Ssimon#endif
23768651Skris	if (out == NULL) goto err;
23859191Skris
23959191Skris#ifndef NO_CHMOD
24055714Skris	chmod(file,0600);
24159191Skris#endif
24255714Skris	n=RAND_DATA;
24355714Skris	for (;;)
24455714Skris		{
24555714Skris		i=(n > BUFSIZE)?BUFSIZE:n;
24655714Skris		n-=BUFSIZE;
24759191Skris		if (RAND_bytes(buf,i) <= 0)
24868651Skris			rand_err=1;
24955714Skris		i=fwrite(buf,1,i,out);
25055714Skris		if (i <= 0)
25155714Skris			{
25255714Skris			ret=0;
25355714Skris			break;
25455714Skris			}
25555714Skris		ret+=i;
25655714Skris		if (n <= 0) break;
25759191Skris                }
25859191Skris
25955714Skris	fclose(out);
260109998Smarkm	OPENSSL_cleanse(buf,BUFSIZE);
26155714Skriserr:
26268651Skris	return (rand_err ? -1 : ret);
26355714Skris	}
26455714Skris
26576866Skrisconst char *RAND_file_name(char *buf, size_t size)
26655714Skris	{
26776866Skris	char *s=NULL;
268215697Ssimon#ifdef __OpenBSD__
269127128Snectar	int ok = 0;
270127128Snectar	struct stat sb;
271127128Snectar#endif
27255714Skris
27376866Skris	if (OPENSSL_issetugid() == 0)
27476866Skris		s=getenv("RANDFILE");
275127128Snectar	if (s != NULL && *s && strlen(s) + 1 < size)
27655714Skris		{
277127128Snectar		if (BUF_strlcpy(buf,s,size) >= size)
278109998Smarkm			return NULL;
27955714Skris		}
28055714Skris	else
28155714Skris		{
28276866Skris		if (OPENSSL_issetugid() == 0)
28376866Skris			s=getenv("HOME");
28479998Skris#ifdef DEFAULT_HOME
28579998Skris		if (s == NULL)
28679998Skris			{
28779998Skris			s = DEFAULT_HOME;
28879998Skris			}
28979998Skris#endif
290127128Snectar		if (s && *s && strlen(s)+strlen(RFILE)+2 < size)
29176866Skris			{
292127128Snectar			BUF_strlcpy(buf,s,size);
293109998Smarkm#ifndef OPENSSL_SYS_VMS
294127128Snectar			BUF_strlcat(buf,"/",size);
29555714Skris#endif
296127128Snectar			BUF_strlcat(buf,RFILE,size);
297215697Ssimon#ifdef __OpenBSD__
298127128Snectar			ok = 1;
299215697Ssimon#endif
30076866Skris			}
30179998Skris		else
30276866Skris		  	buf[0] = '\0'; /* no file name */
30355714Skris		}
304127128Snectar
305127128Snectar#ifdef __OpenBSD__
306127128Snectar	/* given that all random loads just fail if the file can't be
307127128Snectar	 * seen on a stat, we stat the file we're returning, if it
308127128Snectar	 * fails, use /dev/arandom instead. this allows the user to
309127128Snectar	 * use their own source for good random data, but defaults
310127128Snectar	 * to something hopefully decent if that isn't available.
311127128Snectar	 */
312127128Snectar
313127128Snectar	if (!ok)
314127128Snectar		if (BUF_strlcpy(buf,"/dev/arandom",size) >= size) {
315127128Snectar			return(NULL);
316127128Snectar		}
317127128Snectar	if (stat(buf,&sb) == -1)
318127128Snectar		if (BUF_strlcpy(buf,"/dev/arandom",size) >= size) {
319127128Snectar			return(NULL);
320127128Snectar		}
321127128Snectar
322127128Snectar#endif
323127128Snectar	return(buf);
32455714Skris	}
325