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