randfile.c 9.4 KB
Newer Older
R
Rich Salz 已提交
1 2
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
R
Rich Salz 已提交
4 5 6 7
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
8 9
 */

D
Dr. Stephen Henson 已提交
10 11
#include "e_os.h"

U
Ulf Möller 已提交
12
#include <errno.h>
13
#include <stdio.h>
B
Ben Laurie 已提交
14 15
#include <stdlib.h>
#include <string.h>
16

17 18
#include <openssl/crypto.h>
#include <openssl/rand.h>
19
#include <openssl/buffer.h>
20

21
#ifdef OPENSSL_SYS_VMS
22
# include <unixio.h>
23
#endif
A
Andy Polyakov 已提交
24 25 26
#ifndef NO_SYS_TYPES_H
# include <sys/types.h>
#endif
27
#ifndef OPENSSL_NO_POSIX_IO
A
Andy Polyakov 已提交
28
# include <sys/stat.h>
29
# include <fcntl.h>
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/*
 * Following should not be needed, and we could have been stricter
 * and demand S_IS*. But some systems just don't comply... Formally
 * below macros are "anatomically incorrect", because normally they
 * would look like ((m) & MASK == TYPE), but since MASK availability
 * is as questionable, we settle for this poor-man fallback...
 */
# if !defined(S_ISBLK)
#  if defined(_S_IFBLK)
#   define S_ISBLK(m) ((m) & _S_IFBLK)
#  elif defined(S_IFBLK)
#   define S_ISBLK(m) ((m) & S_IFBLK)
#  elif defined(_WIN32)
#   define S_ISBLK(m) 0 /* no concept of block devices on Windows */
#  endif
# endif
# if !defined(S_ISCHR)
#  if defined(_S_IFCHR)
#   define S_ISCHR(m) ((m) & _S_IFCHR)
#  elif defined(S_IFCHR)
#   define S_ISCHR(m) ((m) & S_IFCHR)
#  endif
# endif
A
Andy Polyakov 已提交
53 54
#endif

55
#ifdef _WIN32
56 57 58 59
# define stat    _stat
# define chmod   _chmod
# define open    _open
# define fdopen  _fdopen
60 61
#endif

62
#undef BUFSIZE
63
#define BUFSIZE 1024
64 65
#define RAND_DATA 1024

66
#ifdef OPENSSL_SYS_VMS
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/*
 * Misc hacks needed for specific cases.
 *
 * __FILE_ptr32 is a type provided by DEC C headers (types.h specifically)
 * to make sure the FILE* is a 32-bit pointer no matter what.  We know that
 * stdio function return this type (a study of stdio.h proves it).
 * Additionally, we create a similar char pointer type for the sake of
 * vms_setbuf below.
 */
# if __INITIAL_POINTER_SIZE == 64
#  pragma pointer_size save
#  pragma pointer_size 32
# endif
typedef char *char_ptr32;
# if __INITIAL_POINTER_SIZE == 64
#  pragma pointer_size restore
# endif

/*
 * On VMS, setbuf() will only take 32-bit pointers, and a compilation
 * with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here.
 * Since we know that the FILE* really is a 32-bit pointer expanded to
 * 64 bits, we also know it's safe to convert it back to a 32-bit pointer.
 * As for the buffer parameter, we only use NULL here, so that passes as
 * well...
 */
static void vms_setbuf(FILE *fp, char *buf)
{
    setbuf((__FILE_ptr32)fp, (char_ptr32)buf);
}
97 98
/*
 * This declaration is a nasty hack to get around vms' extension to fopen for
99
 * passing in sharing options being disabled by /STANDARD=ANSI89
100
 */
101 102
static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) =
    (__FILE_ptr32 (*)(const char *, const char *, ...))fopen;
103
# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
104 105 106

# define fopen(fname,mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS)
# define setbuf(fp,buf) vms_setbuf((fp), (buf))
107 108
#endif

R
Rich Salz 已提交
109
#define RFILE ".rnd"
110

111 112 113 114
/*
 * Note that these functions are intended for seed files only. Entropy
 * devices and EGD sockets are handled in rand_unix.c
 */
115

U
Ulf Möller 已提交
116
int RAND_load_file(const char *file, long bytes)
117
{
M
Matt Caswell 已提交
118 119 120 121
    /*-
     * If bytes >= 0, read up to 'bytes' bytes.
     * if bytes == -1, read complete file.
     */
122

123
    unsigned char buf[BUFSIZE];
124
#ifndef OPENSSL_NO_POSIX_IO
125
    struct stat sb;
126
#endif
127 128
    int i, ret = 0, n;
    FILE *in;
129

130 131
    if (file == NULL)
        return (0);
132

133
#ifndef OPENSSL_NO_POSIX_IO
134 135 136 137 138 139 140 141 142 143
    /*
     * struct stat can have padding and unused fields that may not be
     * initialized in the call to stat(). We need to clear the entire
     * structure before calling RAND_add() to avoid complaints from
     * applications such as Valgrind.
     */
    memset(&sb, 0, sizeof(sb));
    if (stat(file, &sb) < 0)
        return (0);
    RAND_add(&sb, sizeof(sb), 0.0);
144
#endif
145 146
    if (bytes == 0)
        return (ret);
147

148 149 150
    in = fopen(file, "rb");
    if (in == NULL)
        goto err;
151 152
#if defined(S_ISBLK) && defined(S_ISCHR) && !defined(OPENSSL_NO_POSIX_IO)
    if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
153 154 155 156 157 158
        /*
         * this file is a device. we don't want read an infinite number of
         * bytes from a random device, nor do we want to use buffered I/O
         * because we will waste system entropy.
         */
        bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
159
        setbuf(in, NULL); /* don't do buffered reads */
160
    }
161
#endif
162 163 164 165 166 167 168 169
    for (;;) {
        if (bytes > 0)
            n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE;
        else
            n = BUFSIZE;
        i = fread(buf, 1, n, in);
        if (i <= 0)
            break;
E
Emilia Kasper 已提交
170

171 172 173 174 175 176 177 178 179 180 181 182 183
        RAND_add(buf, i, (double)i);
        ret += i;
        if (bytes > 0) {
            bytes -= n;
            if (bytes <= 0)
                break;
        }
    }
    fclose(in);
    OPENSSL_cleanse(buf, BUFSIZE);
 err:
    return (ret);
}
184

U
Ulf Möller 已提交
185
int RAND_write_file(const char *file)
186 187 188 189 190
{
    unsigned char buf[BUFSIZE];
    int i, ret = 0, rand_err = 0;
    FILE *out = NULL;
    int n;
191
#ifndef OPENSSL_NO_POSIX_IO
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    struct stat sb;

    i = stat(file, &sb);
    if (i != -1) {
# if defined(S_ISBLK) && defined(S_ISCHR)
        if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
            /*
             * this file is a device. we don't write back to it. we
             * "succeed" on the assumption this is some sort of random
             * device. Otherwise attempting to write to and chmod the device
             * causes problems.
             */
            return (1);
        }
# endif
    }
208
#endif
209

210
#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS)
211 212 213 214 215 216 217 218 219 220 221 222
    {
# ifndef O_BINARY
#  define O_BINARY 0
# endif
        /*
         * chmod(..., 0600) is too late to protect the file, permissions
         * should be restrictive from the start
         */
        int fd = open(file, O_WRONLY | O_CREAT | O_BINARY, 0600);
        if (fd != -1)
            out = fdopen(fd, "wb");
    }
A
Andy Polyakov 已提交
223
#endif
224 225

#ifdef OPENSSL_SYS_VMS
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
    /*
     * VMS NOTE: Prior versions of this routine created a _new_ version of
     * the rand file for each call into this routine, then deleted all
     * existing versions named ;-1, and finally renamed the current version
     * as ';1'. Under concurrent usage, this resulted in an RMS race
     * condition in rename() which could orphan files (see vms message help
     * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares
     * the top-level version of the rand file. Note that there may still be
     * conditions where the top-level rand file is locked. If so, this code
     * will then create a new version of the rand file. Without the delete
     * and rename code, this can result in ascending file versions that stop
     * at version 32767, and this routine will then return an error. The
     * remedy for this is to recode the calling application to avoid
     * concurrent use of the rand file, or synchronize usage at the
     * application level. Also consider whether or not you NEED a persistent
     * rand file in a concurrent use situation.
     */
243

244 245
    out = fopen(file, "rb+");
#endif
246 247 248 249
    if (out == NULL)
        out = fopen(file, "wb");
    if (out == NULL)
        goto err;
250

M
Matt Caswell 已提交
251
#if !defined(NO_CHMOD) && !defined(OPENSSL_NO_POSIX_IO)
252
    chmod(file, 0600);
A
Andy Polyakov 已提交
253
#endif
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    n = RAND_DATA;
    for (;;) {
        i = (n > BUFSIZE) ? BUFSIZE : n;
        n -= BUFSIZE;
        if (RAND_bytes(buf, i) <= 0)
            rand_err = 1;
        i = fwrite(buf, 1, i, out);
        if (i <= 0) {
            ret = 0;
            break;
        }
        ret += i;
        if (n <= 0)
            break;
    }
269

270 271 272 273 274
    fclose(out);
    OPENSSL_cleanse(buf, BUFSIZE);
 err:
    return (rand_err ? -1 : ret);
}
275

276
const char *RAND_file_name(char *buf, size_t size)
277 278
{
    char *s = NULL;
279
#ifdef __OpenBSD__
280
    struct stat sb;
281
#endif
282

283 284 285
    if (OPENSSL_issetugid() == 0)
        s = getenv("RANDFILE");
    if (s != NULL && *s && strlen(s) + 1 < size) {
R
Rich Salz 已提交
286
        if (OPENSSL_strlcpy(buf, s, size) >= size)
287 288
            return NULL;
    } else {
289
#ifdef OPENSSL_SYS_WINDOWS
290 291 292
        if ((s = getenv("HOME")) == NULL
            && (s = getenv("USERPROFILE")) == NULL) {
            s = getenv("SYSTEMROOT");
293 294
        }
#else
295 296
        if (OPENSSL_issetugid() == 0)
            s = getenv("HOME");
297
#endif
298
#ifdef DEFAULT_HOME
299 300 301
        if (s == NULL) {
            s = DEFAULT_HOME;
        }
302
#endif
303
        if (s && *s && strlen(s) + strlen(RFILE) + 2 < size) {
R
Rich Salz 已提交
304
            OPENSSL_strlcpy(buf, s, size);
305
#ifndef OPENSSL_SYS_VMS
R
Rich Salz 已提交
306
            OPENSSL_strlcat(buf, "/", size);
U
Ulf Möller 已提交
307
#endif
R
Rich Salz 已提交
308
            OPENSSL_strlcat(buf, RFILE, size);
309 310 311
        } else
            buf[0] = '\0';      /* no file name */
    }
312 313

#ifdef __OpenBSD__
314 315 316 317 318 319 320
    /*
     * given that all random loads just fail if the file can't be seen on a
     * stat, we stat the file we're returning, if it fails, use /dev/arandom
     * instead. this allows the user to use their own source for good random
     * data, but defaults to something hopefully decent if that isn't
     * available.
     */
321

322
    if (!buf[0])
R
Rich Salz 已提交
323
        if (OPENSSL_strlcpy(buf, "/dev/arandom", size) >= size) {
324 325 326
            return (NULL);
        }
    if (stat(buf, &sb) == -1)
R
Rich Salz 已提交
327
        if (OPENSSL_strlcpy(buf, "/dev/arandom", size) >= size) {
328 329
            return (NULL);
        }
330
#endif
331 332
    return (buf);
}