Add --with-rand-seed
[openssl.git] / crypto / rand / rand_unix.c
1 /*
2  * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdio.h>
11
12 #include "e_os.h"
13 #include "internal/cryptlib.h"
14 #include <openssl/rand.h>
15 #include "rand_lcl.h"
16 #include <stdio.h>
17
18 #if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI))
19
20 # if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \
21         !defined(OPENSSL_RAND_SEED_NONE)
22 #  error "UEFI and VXWorks only support seeding NONE"
23 # endif
24
25 # if defined(OPENSSL_SYS_VOS)
26
27 #  ifndef OPENSSL_RAND_SEED_OS
28 #   error "Unsupported seeding method configured; must be os"
29 #  endif
30
31 #  if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32)
32 #   error "Unsupported HP-PA and IA32 at the same time."
33 #  endif
34 #  if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32)
35 #   error "Must have one of HP-PA or IA32"
36 #  endif
37
38 /*
39  * The following algorithm repeatedly samples the real-time clock (RTC) to
40  * generate a sequence of unpredictable data.  The algorithm relies upon the
41  * uneven execution speed of the code (due to factors such as cache misses,
42  * interrupts, bus activity, and scheduling) and upon the rather large
43  * relative difference between the speed of the clock and the rate at which
44  * it can be read.
45  *
46  * If this code is ported to an environment where execution speed is more
47  * constant or where the RTC ticks at a much slower rate, or the clock can be
48  * read with fewer instructions, it is likely that the results would be far
49  * more predictable.
50  *
51  * As a precaution, we generate 4 times the minimum required amount of seed
52  * data.
53  */
54 int RAND_poll(void)
55 {
56     short int code;
57     gid_t curr_gid;
58     pid_t curr_pid;
59     uid_t curr_uid;
60     int i, k;
61     struct timespec ts;
62     unsigned char v;
63 #  ifdef OPENSSL_SYS_VOS_HPPA
64     long duration;
65     extern void s$sleep(long *_duration, short int *_code);
66 #  else
67     long long duration;
68     extern void s$sleep2(long long *_duration, short int *_code);
69 #  endif
70
71     /*
72      * Seed with the gid, pid, and uid, to ensure *some* variation between
73      * different processes.
74      */
75     curr_gid = getgid();
76     RAND_add(&curr_gid, sizeof curr_gid, 0);
77     curr_pid = getpid();
78     RAND_add(&curr_pid, sizeof curr_pid, 0);
79     curr_uid = getuid();
80     RAND_add(&curr_uid, sizeof curr_uid, 0);
81
82     for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) {
83         /*
84          * burn some cpu; hope for interrupts, cache collisions, bus
85          * interference, etc.
86          */
87         for (k = 0; k < 99; k++)
88             ts.tv_nsec = random();
89
90 #  ifdef OPENSSL_SYS_VOS_HPPA
91         /* sleep for 1/1024 of a second (976 us).  */
92         duration = 1;
93         s$sleep(&duration, &code);
94 #  else
95         /* sleep for 1/65536 of a second (15 us).  */
96         duration = 1;
97         s$sleep2(&duration, &code);
98 #  endif
99
100         /* Get wall clock time, take 8 bits. */
101         clock_gettime(CLOCK_REALTIME, &ts);
102         v = (unsigned char)(ts.tv_nsec & 0xFF);
103         RAND_add(&v, sizeof v, 1);
104     }
105     return 1;
106 }
107
108 # else
109
110 #  if defined(OPENSSL_RAND_SEED_EGD) && \
111         (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD))
112 #   error "Seeding uses EGD but EGD is turned off or no device given"
113 #  endif
114
115 #  if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM)
116 #   error "Seeding uses urandom but DEVRANDOM is not configured"
117 #  endif
118
119 #  if defined(OPENSSL_RAND_SEED_OS)
120 #   if defined(DEVRANDOM)
121 #    define OPENSSL_RAND_SEED_DEVRANDOM
122 #   else
123 #    error "OS seeding requires DEVRANDOM to be configured"
124 #   endif
125 #  endif
126
127 #  if defined(OPENSSL_RAND_SEED_LIBRANDOM)
128 #   error "librandom not (yet) supported"
129 #  endif
130
131 int RAND_poll(void)
132 {
133 #  ifdef OPENSSL_RAND_SEED_NONE
134     return 0;
135 #  else
136     int ok = 0;
137     char temp[RANDOMNESS_NEEDED];
138 #   define TEMPSIZE (int)sizeof(temp)
139
140 #   ifdef OPENSSL_RAND_SEED_RDTSC
141     rand_rdtsc();
142 #   endif
143
144 #   ifdef OPENSSL_RAND_SEED_RDCPU
145     if (rand_rdcpu())
146         ok++;
147 #   endif
148
149 #   ifdef OPENSSL_RAND_SEED_EGD
150     {
151         static const char *paths[] = { DEVRANDOM_EGD, NULL };
152         int i;
153
154         for (i = 0; paths[i] != NULL; i++) {
155             if (RAND_query_egd_bytes(paths[i], temp, TEMPSIZE) == TEMPSIZE) {
156                 RAND_add(temp, TEMPSIZE, TEMPSIZE);
157                 ok++;
158                 break;
159             }
160         }
161     }
162 #   endif
163
164 #   ifdef OPENSSL_RAND_SEED_DEVRANDOM
165     {
166         static const char *paths[] = { DEVRANDOM, NULL };
167         FILE *fp;
168         int i;
169
170         for (i = 0; paths[i] != NULL; i++) {
171             if ((fp = fopen(paths[i], "rb")) == NULL)
172                 continue;
173             setbuf(fp, NULL);
174             if (fread(temp, 1, TEMPSIZE, fp) == TEMPSIZE) {
175                 RAND_add(temp, TEMPSIZE, TEMPSIZE);
176                 ok++;
177                 fclose(fp);
178                 break;
179             }
180         }
181     }
182 #   endif
183
184 #   ifdef OPENSSL_RAND_SEED_GETRANDOM
185     {
186         int i = getrandom(temp, TEMPSIZE, 0);
187
188         if (i >= 0) {
189             RAND_add(temp, i, i);
190             if (i == TEMPSIZE)
191                 ok++;
192         }
193     }
194 #   endif
195
196     OPENSSL_cleanse(temp, TEMPSIZE);
197     return ok > 0 ? 1 : 0;
198 #  endif
199 }
200 # endif
201
202 #endif