rand_unix.c 5.7 KB
Newer Older
R
Rich Salz 已提交
1
/*
R
Rich Salz 已提交
2
 * Copyright 1995-2017 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
 */
R
Rich Salz 已提交
9

10
#include "e_os.h"
11
#include <stdio.h>
12
#include "internal/cryptlib.h"
13 14
#include <openssl/rand.h>
#include "rand_lcl.h"
R
Rich Salz 已提交
15
#include <stdio.h>
16

R
Rich Salz 已提交
17
#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI))
18

R
Rich Salz 已提交
19 20 21
# if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \
        !defined(OPENSSL_RAND_SEED_NONE)
#  error "UEFI and VXWorks only support seeding NONE"
22 23 24 25
# endif

# if defined(OPENSSL_SYS_VOS)

R
Rich Salz 已提交
26 27 28 29 30 31 32 33 34 35 36
#  ifndef OPENSSL_RAND_SEED_OS
#   error "Unsupported seeding method configured; must be os"
#  endif

#  if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32)
#   error "Unsupported HP-PA and IA32 at the same time."
#  endif
#  if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32)
#   error "Must have one of HP-PA or IA32"
#  endif

37 38 39 40 41 42
/*
 * The following algorithm repeatedly samples the real-time clock (RTC) to
 * generate a sequence of unpredictable data.  The algorithm relies upon the
 * uneven execution speed of the code (due to factors such as cache misses,
 * interrupts, bus activity, and scheduling) and upon the rather large
 * relative difference between the speed of the clock and the rate at which
R
Rich Salz 已提交
43 44 45 46 47
 * it can be read.  If it is ported to an environment where execution speed
 * is more constant or where the RTC ticks at a much slower rate, or the
 * clock can be read with fewer instructions, it is likely that the results
 * would be far more predictable.  This should only be used for legacy
 * platforms.
48
 *
R
Rich Salz 已提交
49
 * As a precaution, we generate four times the required amount of seed
50 51
 * data.
 */
52
int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
D
Dr. Stephen Henson 已提交
53
{
54 55 56 57 58 59 60 61 62 63 64 65 66
    short int code;
    gid_t curr_gid;
    pid_t curr_pid;
    uid_t curr_uid;
    int i, k;
    struct timespec ts;
    unsigned char v;
#  ifdef OPENSSL_SYS_VOS_HPPA
    long duration;
    extern void s$sleep(long *_duration, short int *_code);
#  else
    long long duration;
    extern void s$sleep2(long long *_duration, short int *_code);
R
Rich Salz 已提交
67
#  endif
68 69 70 71 72 73

    /*
     * Seed with the gid, pid, and uid, to ensure *some* variation between
     * different processes.
     */
    curr_gid = getgid();
74
    rand_add(arg, &curr_gid, sizeof curr_gid, 0);
75
    curr_pid = getpid();
76
    rand_add(arg, &curr_pid, sizeof curr_pid, 0);
77
    curr_uid = getuid();
78
    rand_add(arg, &curr_uid, sizeof curr_uid, 0);
79

R
Rich Salz 已提交
80
    for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) {
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
        /*
         * burn some cpu; hope for interrupts, cache collisions, bus
         * interference, etc.
         */
        for (k = 0; k < 99; k++)
            ts.tv_nsec = random();

#  ifdef OPENSSL_SYS_VOS_HPPA
        /* sleep for 1/1024 of a second (976 us).  */
        duration = 1;
        s$sleep(&duration, &code);
#  else
        /* sleep for 1/65536 of a second (15 us).  */
        duration = 1;
        s$sleep2(&duration, &code);
R
Rich Salz 已提交
96
#  endif
97

R
Rich Salz 已提交
98
        /* Get wall clock time, take 8 bits. */
99
        clock_gettime(CLOCK_REALTIME, &ts);
R
Rich Salz 已提交
100
        v = (unsigned char)(ts.tv_nsec & 0xFF);
101
        rand_add(arg, &v, sizeof v, 1);
102 103
    }
    return 1;
D
Dr. Stephen Henson 已提交
104
}
R
Rich Salz 已提交
105

R
Rich Salz 已提交
106
# else
R
Rich Salz 已提交
107 108 109 110

#  if defined(OPENSSL_RAND_SEED_EGD) && \
        (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD))
#   error "Seeding uses EGD but EGD is turned off or no device given"
111 112
#  endif

R
Rich Salz 已提交
113 114 115
#  if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM)
#   error "Seeding uses urandom but DEVRANDOM is not configured"
#  endif
116

R
Rich Salz 已提交
117 118 119 120 121
#  if defined(OPENSSL_RAND_SEED_OS)
#   if defined(DEVRANDOM)
#    define OPENSSL_RAND_SEED_DEVRANDOM
#   else
#    error "OS seeding requires DEVRANDOM to be configured"
122
#   endif
R
Rich Salz 已提交
123
#  endif
124

R
Rich Salz 已提交
125 126 127
#  if defined(OPENSSL_RAND_SEED_LIBRANDOM)
#   error "librandom not (yet) supported"
#  endif
128

R
Rich Salz 已提交
129 130 131
/*
 * Try the various seeding methods in turn, exit when succesful.
 */
132
int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
R
Rich Salz 已提交
133 134 135 136
{
#  ifdef OPENSSL_RAND_SEED_NONE
    return 0;
#  else
R
Rich Salz 已提交
137
    int ok = 1;
R
Rich Salz 已提交
138 139
    char temp[RANDOMNESS_NEEDED];
#   define TEMPSIZE (int)sizeof(temp)
140

R
Rich Salz 已提交
141 142 143
#   ifdef OPENSSL_RAND_SEED_GETRANDOM
    {
        int i = getrandom(temp, TEMPSIZE, 0);
144

R
Rich Salz 已提交
145
        if (i >= 0) {
146
            rand_add(arg, temp, i, i);
R
Rich Salz 已提交
147 148 149 150
            if (i == TEMPSIZE)
                goto done;
        }
    }
151 152
#   endif

R
Rich Salz 已提交
153
#   if defined(OPENSSL_RAND_SEED_LIBRANDOM)
R
Rich Salz 已提交
154
    {
R
Rich Salz 已提交
155
        /* Not yet implemented. */
156
    }
R
Rich Salz 已提交
157
#   endif
158

R
Rich Salz 已提交
159 160 161 162 163
#   ifdef OPENSSL_RAND_SEED_DEVRANDOM
    {
        static const char *paths[] = { DEVRANDOM, NULL };
        FILE *fp;
        int i;
164

R
Rich Salz 已提交
165 166 167 168 169
        for (i = 0; paths[i] != NULL; i++) {
            if ((fp = fopen(paths[i], "rb")) == NULL)
                continue;
            setbuf(fp, NULL);
            if (fread(temp, 1, TEMPSIZE, fp) == TEMPSIZE) {
170
                rand_add(arg, temp, TEMPSIZE, TEMPSIZE);
R
Rich Salz 已提交
171
                fclose(fp);
R
Rich Salz 已提交
172
                goto done;
R
Rich Salz 已提交
173
            }
R
Rich Salz 已提交
174
            fclose(fp);
R
Rich Salz 已提交
175
        }
176
    }
R
Rich Salz 已提交
177
#   endif
178

R
Rich Salz 已提交
179
#   ifdef OPENSSL_RAND_SEED_RDTSC
180
    rand_read_tsc(rand_add, arg);
R
Rich Salz 已提交
181 182 183
#   endif

#   ifdef OPENSSL_RAND_SEED_RDCPU
184
    if (rand_read_cpu(rand_add, arg))
R
Rich Salz 已提交
185 186 187 188
        goto done;
#   endif

#   ifdef OPENSSL_RAND_SEED_EGD
R
Rich Salz 已提交
189
    {
R
Rich Salz 已提交
190 191
        static const char *paths[] = { DEVRANDOM_EGD, NULL };
        int i;
192

R
Rich Salz 已提交
193 194
        for (i = 0; paths[i] != NULL; i++) {
            if (RAND_query_egd_bytes(paths[i], temp, TEMPSIZE) == TEMPSIZE) {
195
                rand_add(arg, temp, TEMPSIZE, TEMPSIZE);
R
Rich Salz 已提交
196 197
                goto done;
            }
R
Rich Salz 已提交
198 199 200
        }
    }
#   endif
201

R
Rich Salz 已提交
202 203 204
    ok = 0;

done:
R
Rich Salz 已提交
205
    OPENSSL_cleanse(temp, TEMPSIZE);
R
Rich Salz 已提交
206
    return ok;
207
#  endif
208
}
R
Rich Salz 已提交
209
# endif
210

211
#endif