eecd544aeef43afe676a94a030e90d649fa927d1
[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.  If it is ported to an environment where execution speed
45  * is more constant or where the RTC ticks at a much slower rate, or the
46  * clock can be read with fewer instructions, it is likely that the results
47  * would be far more predictable.  This should only be used for legacy
48  * platforms.
49  *
50  * As a precaution, we generate four times the required amount of seed
51  * data.
52  */
53 int RAND_poll_ex(RAND_poll_fn cb, void *arg)
54 {
55     short int code;
56     gid_t curr_gid;
57     pid_t curr_pid;
58     uid_t curr_uid;
59     int i, k;
60     struct timespec ts;
61     unsigned char v;
62 #  ifdef OPENSSL_SYS_VOS_HPPA
63     long duration;
64     extern void s$sleep(long *_duration, short int *_code);
65 #  else
66     long long duration;
67     extern void s$sleep2(long long *_duration, short int *_code);
68 #  endif
69
70     /*
71      * Seed with the gid, pid, and uid, to ensure *some* variation between
72      * different processes.
73      */
74     curr_gid = getgid();
75     cb(arg, &curr_gid, sizeof curr_gid, 0);
76     curr_pid = getpid();
77     cb(arg, &curr_pid, sizeof curr_pid, 0);
78     curr_uid = getuid();
79     cb(arg, &curr_uid, sizeof curr_uid, 0);
80
81     for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) {
82         /*
83          * burn some cpu; hope for interrupts, cache collisions, bus
84          * interference, etc.
85          */
86         for (k = 0; k < 99; k++)
87             ts.tv_nsec = random();
88
89 #  ifdef OPENSSL_SYS_VOS_HPPA
90         /* sleep for 1/1024 of a second (976 us).  */
91         duration = 1;
92         s$sleep(&duration, &code);
93 #  else
94         /* sleep for 1/65536 of a second (15 us).  */
95         duration = 1;
96         s$sleep2(&duration, &code);
97 #  endif
98
99         /* Get wall clock time, take 8 bits. */
100         clock_gettime(CLOCK_REALTIME, &ts);
101         v = (unsigned char)(ts.tv_nsec & 0xFF);
102         cb(arg, &v, sizeof v, 1);
103     }
104     return 1;
105 }
106
107 # else
108
109 #  if defined(OPENSSL_RAND_SEED_EGD) && \
110         (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD))
111 #   error "Seeding uses EGD but EGD is turned off or no device given"
112 #  endif
113
114 #  if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM)
115 #   error "Seeding uses urandom but DEVRANDOM is not configured"
116 #  endif
117
118 #  if defined(OPENSSL_RAND_SEED_OS)
119 #   if defined(DEVRANDOM)
120 #    define OPENSSL_RAND_SEED_DEVRANDOM
121 #   else
122 #    error "OS seeding requires DEVRANDOM to be configured"
123 #   endif
124 #  endif
125
126 #  if defined(OPENSSL_RAND_SEED_LIBRANDOM)
127 #   error "librandom not (yet) supported"
128 #  endif
129
130 /*
131  * Try the various seeding methods in turn, exit when succesful.
132  */
133 int RAND_poll_ex(RAND_poll_fn cb, void *arg)
134 {
135 #  ifdef OPENSSL_RAND_SEED_NONE
136     return 0;
137 #  else
138     int ok = 1;
139     char temp[RANDOMNESS_NEEDED];
140 #   define TEMPSIZE (int)sizeof(temp)
141
142 #   ifdef OPENSSL_RAND_SEED_GETRANDOM
143     {
144         int i = getrandom(temp, TEMPSIZE, 0);
145
146         if (i >= 0) {
147             cb(arg, temp, i, i);
148             if (i == TEMPSIZE)
149                 goto done;
150         }
151     }
152 #   endif
153
154 #   if defined(OPENSSL_RAND_SEED_LIBRANDOM)
155     {
156         /* Not yet implemented. */
157     }
158 #   endif
159
160 #   ifdef OPENSSL_RAND_SEED_DEVRANDOM
161     {
162         static const char *paths[] = { DEVRANDOM, NULL };
163         FILE *fp;
164         int i;
165
166         for (i = 0; paths[i] != NULL; i++) {
167             if ((fp = fopen(paths[i], "rb")) == NULL)
168                 continue;
169             setbuf(fp, NULL);
170             if (fread(temp, 1, TEMPSIZE, fp) == TEMPSIZE) {
171                 cb(arg, temp, TEMPSIZE, TEMPSIZE);
172                 fclose(fp);
173                 goto done;
174             }
175             fclose(fp);
176         }
177     }
178 #   endif
179
180 #   ifdef OPENSSL_RAND_SEED_RDTSC
181     rand_read_tsc(cb, arg);
182 #   endif
183
184 #   ifdef OPENSSL_RAND_SEED_RDCPU
185     if (rand_read_cpu(cb, arg))
186         goto done;
187 #   endif
188
189 #   ifdef OPENSSL_RAND_SEED_EGD
190     {
191         static const char *paths[] = { DEVRANDOM_EGD, NULL };
192         int i;
193
194         for (i = 0; paths[i] != NULL; i++) {
195             if (RAND_query_egd_bytes(paths[i], temp, TEMPSIZE) == TEMPSIZE) {
196                 cb(arg, temp, TEMPSIZE, TEMPSIZE);
197                 goto done;
198             }
199         }
200     }
201 #   endif
202
203     ok = 0;
204
205 done:
206     OPENSSL_cleanse(temp, TEMPSIZE);
207     return ok;
208 #  endif
209 }
210 # endif
211
212 #endif