randfile.c revision 269682
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 */
60246772Sjkim#if !defined(OPENSSL_SYS_VXWORKS)
61160814Ssimon#define _XOPEN_SOURCE 500
62246772Sjkim#endif
63127128Snectar
6455714Skris#include <errno.h>
6555714Skris#include <stdio.h>
6655714Skris#include <stdlib.h>
6755714Skris#include <string.h>
6855714Skris
69109998Smarkm#include "e_os.h"
70109998Smarkm#include <openssl/crypto.h>
71109998Smarkm#include <openssl/rand.h>
72127128Snectar#include <openssl/buffer.h>
73109998Smarkm
74109998Smarkm#ifdef OPENSSL_SYS_VMS
7559191Skris#include <unixio.h>
7659191Skris#endif
7759191Skris#ifndef NO_SYS_TYPES_H
7859191Skris# include <sys/types.h>
7959191Skris#endif
80238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
8159191Skris# include <sys/stat.h>
82269682Sjkim# include <fcntl.h>
8359191Skris#endif
8459191Skris
85194206Ssimon#ifdef _WIN32
86194206Ssimon#define stat	_stat
87194206Ssimon#define chmod	_chmod
88194206Ssimon#define open	_open
89194206Ssimon#define fdopen	_fdopen
90194206Ssimon#endif
91194206Ssimon
9255714Skris#undef BUFSIZE
9355714Skris#define BUFSIZE	1024
9455714Skris#define RAND_DATA 1024
9555714Skris
96194206Ssimon#ifdef OPENSSL_SYS_VMS
97194206Ssimon/* This declaration is a nasty hack to get around vms' extension to fopen
98194206Ssimon * for passing in sharing options being disabled by our /STANDARD=ANSI89 */
99194206Ssimonstatic FILE *(*const vms_fopen)(const char *, const char *, ...) =
100194206Ssimon    (FILE *(*)(const char *, const char *, ...))fopen;
101194206Ssimon#define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
102194206Ssimon#endif
103194206Ssimon
10459191Skris/* #define RFILE ".rnd" - defined in ../../e_os.h */
10555714Skris
10672613Skris/* Note that these functions are intended for seed files only.
10772613Skris * Entropy devices and EGD sockets are handled in rand_unix.c */
10872613Skris
10955714Skrisint RAND_load_file(const char *file, long bytes)
11055714Skris	{
11159191Skris	/* If bytes >= 0, read up to 'bytes' bytes.
11259191Skris	 * if bytes == -1, read complete file. */
11359191Skris
11455714Skris	MS_STATIC unsigned char buf[BUFSIZE];
115238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
11655714Skris	struct stat sb;
117238405Sjkim#endif
11855714Skris	int i,ret=0,n;
11955714Skris	FILE *in;
12055714Skris
12155714Skris	if (file == NULL) return(0);
12255714Skris
123238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
124205128Ssimon#ifdef PURIFY
125205128Ssimon	/* struct stat can have padding and unused fields that may not be
126205128Ssimon	 * initialized in the call to stat(). We need to clear the entire
127205128Ssimon	 * structure before calling RAND_add() to avoid complaints from
128205128Ssimon	 * applications such as Valgrind.
129205128Ssimon	 */
130205128Ssimon	memset(&sb, 0, sizeof(sb));
131205128Ssimon#endif
132194206Ssimon	if (stat(file,&sb) < 0) return(0);
133160814Ssimon	RAND_add(&sb,sizeof(sb),0.0);
134238405Sjkim#endif
13559191Skris	if (bytes == 0) return(ret);
13655714Skris
137194206Ssimon#ifdef OPENSSL_SYS_VMS
138194206Ssimon	in=vms_fopen(file,"rb",VMS_OPEN_ATTRS);
139194206Ssimon#else
14055714Skris	in=fopen(file,"rb");
141194206Ssimon#endif
14255714Skris	if (in == NULL) goto err;
143238405Sjkim#if defined(S_IFBLK) && defined(S_IFCHR) && !defined(OPENSSL_NO_POSIX_IO)
144238405Sjkim	if (sb.st_mode & (S_IFBLK | S_IFCHR)) {
145127128Snectar	  /* this file is a device. we don't want read an infinite number
146127128Snectar	   * of bytes from a random device, nor do we want to use buffered
147127128Snectar	   * I/O because we will waste system entropy.
148127128Snectar	   */
149127128Snectar	  bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
150238405Sjkim#ifndef OPENSSL_NO_SETVBUF_IONBF
151127128Snectar	  setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */
152238405Sjkim#endif /* ndef OPENSSL_NO_SETVBUF_IONBF */
153127128Snectar	}
154127128Snectar#endif
15555714Skris	for (;;)
15655714Skris		{
15759191Skris		if (bytes > 0)
15859191Skris			n = (bytes < BUFSIZE)?(int)bytes:BUFSIZE;
15959191Skris		else
16059191Skris			n = BUFSIZE;
16155714Skris		i=fread(buf,1,n,in);
16255714Skris		if (i <= 0) break;
163194206Ssimon#ifdef PURIFY
164194206Ssimon		RAND_add(buf,i,(double)i);
165194206Ssimon#else
16655714Skris		/* even if n != i, use the full array */
167160814Ssimon		RAND_add(buf,n,(double)i);
168194206Ssimon#endif
16955714Skris		ret+=i;
17059191Skris		if (bytes > 0)
17159191Skris			{
17259191Skris			bytes-=n;
17372613Skris			if (bytes <= 0) break;
17459191Skris			}
17555714Skris		}
17655714Skris	fclose(in);
177109998Smarkm	OPENSSL_cleanse(buf,BUFSIZE);
17855714Skriserr:
17955714Skris	return(ret);
18055714Skris	}
18155714Skris
18255714Skrisint RAND_write_file(const char *file)
18355714Skris	{
18455714Skris	unsigned char buf[BUFSIZE];
18568651Skris	int i,ret=0,rand_err=0;
18659191Skris	FILE *out = NULL;
18755714Skris	int n;
188238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
189127128Snectar	struct stat sb;
19059191Skris
191127128Snectar	i=stat(file,&sb);
192127128Snectar	if (i != -1) {
193205128Ssimon#if defined(S_ISBLK) && defined(S_ISCHR)
194205128Ssimon	  if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
195127128Snectar	    /* this file is a device. we don't write back to it.
196127128Snectar	     * we "succeed" on the assumption this is some sort
197127128Snectar	     * of random device. Otherwise attempting to write to
198127128Snectar	     * and chmod the device causes problems.
199127128Snectar	     */
200127128Snectar	    return(1);
201127128Snectar	  }
202127128Snectar#endif
203127128Snectar	}
204238405Sjkim#endif
205127128Snectar
206238405Sjkim#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS)
207142425Snectar	{
208238405Sjkim#ifndef O_BINARY
209238405Sjkim#define O_BINARY 0
210238405Sjkim#endif
21168651Skris	/* chmod(..., 0600) is too late to protect the file,
21268651Skris	 * permissions should be restrictive from the start */
213238405Sjkim	int fd = open(file, O_WRONLY|O_CREAT|O_BINARY, 0600);
21468651Skris	if (fd != -1)
21568651Skris		out = fdopen(fd, "wb");
216142425Snectar	}
21759191Skris#endif
218194206Ssimon
219194206Ssimon#ifdef OPENSSL_SYS_VMS
220194206Ssimon	/* VMS NOTE: Prior versions of this routine created a _new_
221194206Ssimon	 * version of the rand file for each call into this routine, then
222194206Ssimon	 * deleted all existing versions named ;-1, and finally renamed
223194206Ssimon	 * the current version as ';1'. Under concurrent usage, this
224194206Ssimon	 * resulted in an RMS race condition in rename() which could
225194206Ssimon	 * orphan files (see vms message help for RMS$_REENT). With the
226194206Ssimon	 * fopen() calls below, openssl/VMS now shares the top-level
227194206Ssimon	 * version of the rand file. Note that there may still be
228194206Ssimon	 * conditions where the top-level rand file is locked. If so, this
229194206Ssimon	 * code will then create a new version of the rand file. Without
230194206Ssimon	 * the delete and rename code, this can result in ascending file
231194206Ssimon	 * versions that stop at version 32767, and this routine will then
232194206Ssimon	 * return an error. The remedy for this is to recode the calling
233194206Ssimon	 * application to avoid concurrent use of the rand file, or
234194206Ssimon	 * synchronize usage at the application level. Also consider
235194206Ssimon	 * whether or not you NEED a persistent rand file in a concurrent
236194206Ssimon	 * use situation.
237194206Ssimon	 */
238194206Ssimon
239194206Ssimon	out = vms_fopen(file,"rb+",VMS_OPEN_ATTRS);
24068651Skris	if (out == NULL)
241194206Ssimon		out = vms_fopen(file,"wb",VMS_OPEN_ATTRS);
242194206Ssimon#else
243194206Ssimon	if (out == NULL)
24468651Skris		out = fopen(file,"wb");
245194206Ssimon#endif
24668651Skris	if (out == NULL) goto err;
24759191Skris
24859191Skris#ifndef NO_CHMOD
24955714Skris	chmod(file,0600);
25059191Skris#endif
25155714Skris	n=RAND_DATA;
25255714Skris	for (;;)
25355714Skris		{
25455714Skris		i=(n > BUFSIZE)?BUFSIZE:n;
25555714Skris		n-=BUFSIZE;
25659191Skris		if (RAND_bytes(buf,i) <= 0)
25768651Skris			rand_err=1;
25855714Skris		i=fwrite(buf,1,i,out);
25955714Skris		if (i <= 0)
26055714Skris			{
26155714Skris			ret=0;
26255714Skris			break;
26355714Skris			}
26455714Skris		ret+=i;
26555714Skris		if (n <= 0) break;
26659191Skris                }
26759191Skris
26855714Skris	fclose(out);
269109998Smarkm	OPENSSL_cleanse(buf,BUFSIZE);
27055714Skriserr:
27168651Skris	return (rand_err ? -1 : ret);
27255714Skris	}
27355714Skris
27476866Skrisconst char *RAND_file_name(char *buf, size_t size)
27555714Skris	{
27676866Skris	char *s=NULL;
277215697Ssimon#ifdef __OpenBSD__
278127128Snectar	struct stat sb;
279127128Snectar#endif
28055714Skris
28176866Skris	if (OPENSSL_issetugid() == 0)
28276866Skris		s=getenv("RANDFILE");
283127128Snectar	if (s != NULL && *s && strlen(s) + 1 < size)
28455714Skris		{
285127128Snectar		if (BUF_strlcpy(buf,s,size) >= size)
286109998Smarkm			return NULL;
28755714Skris		}
28855714Skris	else
28955714Skris		{
29076866Skris		if (OPENSSL_issetugid() == 0)
29176866Skris			s=getenv("HOME");
29279998Skris#ifdef DEFAULT_HOME
29379998Skris		if (s == NULL)
29479998Skris			{
29579998Skris			s = DEFAULT_HOME;
29679998Skris			}
29779998Skris#endif
298127128Snectar		if (s && *s && strlen(s)+strlen(RFILE)+2 < size)
29976866Skris			{
300127128Snectar			BUF_strlcpy(buf,s,size);
301109998Smarkm#ifndef OPENSSL_SYS_VMS
302127128Snectar			BUF_strlcat(buf,"/",size);
30355714Skris#endif
304127128Snectar			BUF_strlcat(buf,RFILE,size);
30576866Skris			}
30679998Skris		else
30776866Skris		  	buf[0] = '\0'; /* no file name */
30855714Skris		}
309127128Snectar
310127128Snectar#ifdef __OpenBSD__
311127128Snectar	/* given that all random loads just fail if the file can't be
312127128Snectar	 * seen on a stat, we stat the file we're returning, if it
313127128Snectar	 * fails, use /dev/arandom instead. this allows the user to
314127128Snectar	 * use their own source for good random data, but defaults
315127128Snectar	 * to something hopefully decent if that isn't available.
316127128Snectar	 */
317127128Snectar
318238405Sjkim	if (!buf[0])
319127128Snectar		if (BUF_strlcpy(buf,"/dev/arandom",size) >= size) {
320127128Snectar			return(NULL);
321127128Snectar		}
322127128Snectar	if (stat(buf,&sb) == -1)
323127128Snectar		if (BUF_strlcpy(buf,"/dev/arandom",size) >= size) {
324127128Snectar			return(NULL);
325127128Snectar		}
326127128Snectar
327127128Snectar#endif
328127128Snectar	return(buf);
32955714Skris	}
330