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.
8280297Sjkim *
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).
15280297Sjkim *
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.
22280297Sjkim *
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 :-).
37280297Sjkim * 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)"
40280297Sjkim *
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.
52280297Sjkim *
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
5955714Skris#include <errno.h>
6055714Skris#include <stdio.h>
6155714Skris#include <stdlib.h>
6255714Skris#include <string.h>
6355714Skris
64340704Sjkim#include "cryptlib.h"
65109998Smarkm#include "e_os.h"
66109998Smarkm#include <openssl/crypto.h>
67109998Smarkm#include <openssl/rand.h>
68127128Snectar#include <openssl/buffer.h>
69109998Smarkm
70109998Smarkm#ifdef OPENSSL_SYS_VMS
71280297Sjkim# include <unixio.h>
7259191Skris#endif
7359191Skris#ifndef NO_SYS_TYPES_H
7459191Skris# include <sys/types.h>
7559191Skris#endif
76238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
7759191Skris# include <sys/stat.h>
78269682Sjkim# include <fcntl.h>
79306195Sjkim/*
80306195Sjkim * Following should not be needed, and we could have been stricter
81306195Sjkim * and demand S_IS*. But some systems just don't comply... Formally
82306195Sjkim * below macros are "anatomically incorrect", because normally they
83306195Sjkim * would look like ((m) & MASK == TYPE), but since MASK availability
84306195Sjkim * is as questionable, we settle for this poor-man fallback...
85306195Sjkim */
86306195Sjkim# if !defined(S_ISBLK)
87306195Sjkim#  if defined(_S_IFBLK)
88306195Sjkim#   define S_ISBLK(m) ((m) & _S_IFBLK)
89306195Sjkim#  elif defined(S_IFBLK)
90306195Sjkim#   define S_ISBLK(m) ((m) & S_IFBLK)
91306195Sjkim#  elif defined(_WIN32)
92306195Sjkim#   define S_ISBLK(m) 0 /* no concept of block devices on Windows */
93306195Sjkim#  endif
94306195Sjkim# endif
95306195Sjkim# if !defined(S_ISCHR)
96306195Sjkim#  if defined(_S_IFCHR)
97306195Sjkim#   define S_ISCHR(m) ((m) & _S_IFCHR)
98306195Sjkim#  elif defined(S_IFCHR)
99306195Sjkim#   define S_ISCHR(m) ((m) & S_IFCHR)
100306195Sjkim#  endif
101306195Sjkim# endif
10259191Skris#endif
10359191Skris
104194206Ssimon#ifdef _WIN32
105280297Sjkim# define stat    _stat
106280297Sjkim# define chmod   _chmod
107280297Sjkim# define open    _open
108280297Sjkim# define fdopen  _fdopen
109194206Ssimon#endif
110194206Ssimon
11155714Skris#undef BUFSIZE
112280297Sjkim#define BUFSIZE 1024
11355714Skris#define RAND_DATA 1024
11455714Skris
115306195Sjkim#if (defined(OPENSSL_SYS_VMS) && (defined(__alpha) || defined(__ia64)))
116280297Sjkim/*
117280297Sjkim * This declaration is a nasty hack to get around vms' extension to fopen for
118280297Sjkim * passing in sharing options being disabled by our /STANDARD=ANSI89
119280297Sjkim */
120194206Ssimonstatic FILE *(*const vms_fopen)(const char *, const char *, ...) =
121194206Ssimon    (FILE *(*)(const char *, const char *, ...))fopen;
122280297Sjkim# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
123194206Ssimon#endif
124194206Ssimon
12559191Skris/* #define RFILE ".rnd" - defined in ../../e_os.h */
12655714Skris
127280297Sjkim/*
128280297Sjkim * Note that these functions are intended for seed files only. Entropy
129280297Sjkim * devices and EGD sockets are handled in rand_unix.c
130280297Sjkim */
13172613Skris
13255714Skrisint RAND_load_file(const char *file, long bytes)
133280297Sjkim{
134280297Sjkim    /*-
135280297Sjkim     * If bytes >= 0, read up to 'bytes' bytes.
136280297Sjkim     * if bytes == -1, read complete file.
137280297Sjkim     */
13859191Skris
139280297Sjkim    MS_STATIC unsigned char buf[BUFSIZE];
140238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
141280297Sjkim    struct stat sb;
142238405Sjkim#endif
143280297Sjkim    int i, ret = 0, n;
144306195Sjkim/*
145306195Sjkim * If setvbuf() is to be called, then the FILE pointer
146306195Sjkim * to it must be 32 bit.
147306195Sjkim*/
148306195Sjkim
149306195Sjkim#if !defined OPENSSL_NO_SETVBUF_IONBF && defined(OPENSSL_SYS_VMS) && defined(__VMS_VER) && (__VMS_VER >= 70000000)
150306195Sjkim    /* For 64-bit-->32 bit API Support*/
151306195Sjkim#if __INITIAL_POINTER_SIZE == 64
152306195Sjkim#pragma __required_pointer_size __save
153306195Sjkim#pragma __required_pointer_size 32
154306195Sjkim#endif
155306195Sjkim    FILE *in; /* setvbuf() requires 32-bit pointers */
156306195Sjkim#if __INITIAL_POINTER_SIZE == 64
157306195Sjkim#pragma __required_pointer_size __restore
158306195Sjkim#endif
159306195Sjkim#else
160280297Sjkim    FILE *in;
161306195Sjkim#endif /* OPENSSL_SYS_VMS */
16255714Skris
163280297Sjkim    if (file == NULL)
164280297Sjkim        return (0);
16555714Skris
166238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
167280297Sjkim# ifdef PURIFY
168280297Sjkim    /*
169280297Sjkim     * struct stat can have padding and unused fields that may not be
170280297Sjkim     * initialized in the call to stat(). We need to clear the entire
171280297Sjkim     * structure before calling RAND_add() to avoid complaints from
172280297Sjkim     * applications such as Valgrind.
173280297Sjkim     */
174280297Sjkim    memset(&sb, 0, sizeof(sb));
175280297Sjkim# endif
176280297Sjkim    if (stat(file, &sb) < 0)
177280297Sjkim        return (0);
178280297Sjkim    RAND_add(&sb, sizeof(sb), 0.0);
179205128Ssimon#endif
180280297Sjkim    if (bytes == 0)
181280297Sjkim        return (ret);
18255714Skris
183194206Ssimon#ifdef OPENSSL_SYS_VMS
184280297Sjkim    in = vms_fopen(file, "rb", VMS_OPEN_ATTRS);
185194206Ssimon#else
186280297Sjkim    in = fopen(file, "rb");
187194206Ssimon#endif
188280297Sjkim    if (in == NULL)
189280297Sjkim        goto err;
190306195Sjkim#if defined(S_ISBLK) && defined(S_ISCHR) && !defined(OPENSSL_NO_POSIX_IO)
191306195Sjkim    if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
192280297Sjkim        /*
193280297Sjkim         * this file is a device. we don't want read an infinite number of
194280297Sjkim         * bytes from a random device, nor do we want to use buffered I/O
195280297Sjkim         * because we will waste system entropy.
196280297Sjkim         */
197280297Sjkim        bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
198280297Sjkim# ifndef OPENSSL_NO_SETVBUF_IONBF
199280297Sjkim        setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */
200280297Sjkim# endif                         /* ndef OPENSSL_NO_SETVBUF_IONBF */
201280297Sjkim    }
202127128Snectar#endif
203280297Sjkim    for (;;) {
204280297Sjkim        if (bytes > 0)
205280297Sjkim            n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE;
206280297Sjkim        else
207280297Sjkim            n = BUFSIZE;
208280297Sjkim        i = fread(buf, 1, n, in);
209280297Sjkim        if (i <= 0)
210280297Sjkim            break;
211194206Ssimon#ifdef PURIFY
212280297Sjkim        RAND_add(buf, i, (double)i);
213194206Ssimon#else
214280297Sjkim        /* even if n != i, use the full array */
215280297Sjkim        RAND_add(buf, n, (double)i);
216194206Ssimon#endif
217280297Sjkim        ret += i;
218280297Sjkim        if (bytes > 0) {
219280297Sjkim            bytes -= n;
220280297Sjkim            if (bytes <= 0)
221280297Sjkim                break;
222280297Sjkim        }
223280297Sjkim    }
224280297Sjkim    fclose(in);
225280297Sjkim    OPENSSL_cleanse(buf, BUFSIZE);
226280297Sjkim err:
227280297Sjkim    return (ret);
228280297Sjkim}
22955714Skris
23055714Skrisint RAND_write_file(const char *file)
231280297Sjkim{
232280297Sjkim    unsigned char buf[BUFSIZE];
233280297Sjkim    int i, ret = 0, rand_err = 0;
234280297Sjkim    FILE *out = NULL;
235280297Sjkim    int n;
236238405Sjkim#ifndef OPENSSL_NO_POSIX_IO
237280297Sjkim    struct stat sb;
238280297Sjkim
239280297Sjkim    i = stat(file, &sb);
240280297Sjkim    if (i != -1) {
241280297Sjkim# if defined(S_ISBLK) && defined(S_ISCHR)
242280297Sjkim        if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
243280297Sjkim            /*
244280297Sjkim             * this file is a device. we don't write back to it. we
245280297Sjkim             * "succeed" on the assumption this is some sort of random
246280297Sjkim             * device. Otherwise attempting to write to and chmod the device
247280297Sjkim             * causes problems.
248280297Sjkim             */
249280297Sjkim            return (1);
250280297Sjkim        }
251280297Sjkim# endif
252280297Sjkim    }
253127128Snectar#endif
254127128Snectar
255238405Sjkim#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS)
256280297Sjkim    {
257280297Sjkim# ifndef O_BINARY
258280297Sjkim#  define O_BINARY 0
259280297Sjkim# endif
260280297Sjkim        /*
261280297Sjkim         * chmod(..., 0600) is too late to protect the file, permissions
262280297Sjkim         * should be restrictive from the start
263280297Sjkim         */
264280297Sjkim        int fd = open(file, O_WRONLY | O_CREAT | O_BINARY, 0600);
265280297Sjkim        if (fd != -1)
266280297Sjkim            out = fdopen(fd, "wb");
267280297Sjkim    }
268238405Sjkim#endif
269194206Ssimon
270306195Sjkim#if (defined(OPENSSL_SYS_VMS) && (defined(__alpha) || defined(__ia64)))
271280297Sjkim    /*
272280297Sjkim     * VMS NOTE: Prior versions of this routine created a _new_ version of
273280297Sjkim     * the rand file for each call into this routine, then deleted all
274280297Sjkim     * existing versions named ;-1, and finally renamed the current version
275280297Sjkim     * as ';1'. Under concurrent usage, this resulted in an RMS race
276280297Sjkim     * condition in rename() which could orphan files (see vms message help
277280297Sjkim     * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares
278280297Sjkim     * the top-level version of the rand file. Note that there may still be
279280297Sjkim     * conditions where the top-level rand file is locked. If so, this code
280280297Sjkim     * will then create a new version of the rand file. Without the delete
281280297Sjkim     * and rename code, this can result in ascending file versions that stop
282280297Sjkim     * at version 32767, and this routine will then return an error. The
283280297Sjkim     * remedy for this is to recode the calling application to avoid
284280297Sjkim     * concurrent use of the rand file, or synchronize usage at the
285280297Sjkim     * application level. Also consider whether or not you NEED a persistent
286280297Sjkim     * rand file in a concurrent use situation.
287280297Sjkim     */
288194206Ssimon
289280297Sjkim    out = vms_fopen(file, "rb+", VMS_OPEN_ATTRS);
290280297Sjkim    if (out == NULL)
291280297Sjkim        out = vms_fopen(file, "wb", VMS_OPEN_ATTRS);
292194206Ssimon#else
293280297Sjkim    if (out == NULL)
294280297Sjkim        out = fopen(file, "wb");
295194206Ssimon#endif
296280297Sjkim    if (out == NULL)
297280297Sjkim        goto err;
29859191Skris
29959191Skris#ifndef NO_CHMOD
300280297Sjkim    chmod(file, 0600);
30159191Skris#endif
302280297Sjkim    n = RAND_DATA;
303280297Sjkim    for (;;) {
304280297Sjkim        i = (n > BUFSIZE) ? BUFSIZE : n;
305280297Sjkim        n -= BUFSIZE;
306280297Sjkim        if (RAND_bytes(buf, i) <= 0)
307280297Sjkim            rand_err = 1;
308280297Sjkim        i = fwrite(buf, 1, i, out);
309280297Sjkim        if (i <= 0) {
310280297Sjkim            ret = 0;
311280297Sjkim            break;
312280297Sjkim        }
313280297Sjkim        ret += i;
314280297Sjkim        if (n <= 0)
315280297Sjkim            break;
316280297Sjkim    }
31759191Skris
318280297Sjkim    fclose(out);
319280297Sjkim    OPENSSL_cleanse(buf, BUFSIZE);
320280297Sjkim err:
321280297Sjkim    return (rand_err ? -1 : ret);
322280297Sjkim}
32355714Skris
32476866Skrisconst char *RAND_file_name(char *buf, size_t size)
325280297Sjkim{
326280297Sjkim    char *s = NULL;
327215697Ssimon#ifdef __OpenBSD__
328280297Sjkim    struct stat sb;
329127128Snectar#endif
33055714Skris
331340704Sjkim    s = ossl_safe_getenv("RANDFILE");
332280297Sjkim    if (s != NULL && *s && strlen(s) + 1 < size) {
333280297Sjkim        if (BUF_strlcpy(buf, s, size) >= size)
334280297Sjkim            return NULL;
335280297Sjkim    } else {
336340704Sjkim        s = ossl_safe_getenv("HOME");
33779998Skris#ifdef DEFAULT_HOME
338280297Sjkim        if (s == NULL) {
339280297Sjkim            s = DEFAULT_HOME;
340280297Sjkim        }
34179998Skris#endif
342280297Sjkim        if (s && *s && strlen(s) + strlen(RFILE) + 2 < size) {
343280297Sjkim            BUF_strlcpy(buf, s, size);
344109998Smarkm#ifndef OPENSSL_SYS_VMS
345280297Sjkim            BUF_strlcat(buf, "/", size);
34655714Skris#endif
347280297Sjkim            BUF_strlcat(buf, RFILE, size);
348280297Sjkim        } else
349280297Sjkim            buf[0] = '\0';      /* no file name */
350280297Sjkim    }
351127128Snectar
352127128Snectar#ifdef __OpenBSD__
353280297Sjkim    /*
354280297Sjkim     * given that all random loads just fail if the file can't be seen on a
355280297Sjkim     * stat, we stat the file we're returning, if it fails, use /dev/arandom
356280297Sjkim     * instead. this allows the user to use their own source for good random
357280297Sjkim     * data, but defaults to something hopefully decent if that isn't
358280297Sjkim     * available.
359280297Sjkim     */
360127128Snectar
361280297Sjkim    if (!buf[0])
362280297Sjkim        if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) {
363280297Sjkim            return (NULL);
364280297Sjkim        }
365280297Sjkim    if (stat(buf, &sb) == -1)
366280297Sjkim        if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) {
367280297Sjkim            return (NULL);
368280297Sjkim        }
369127128Snectar#endif
370280297Sjkim    return (buf);
371280297Sjkim}
372