]>
Commit | Line | Data |
---|---|---|
b1322259 | 1 | /* |
0d664759 | 2 | * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. |
0c61e299 | 3 | * |
b1322259 RS |
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 | |
0c61e299 | 8 | */ |
b1322259 | 9 | |
da0616cd | 10 | #include "e_os.h" |
07016a8a | 11 | #include <stdio.h> |
b39fc560 | 12 | #include "internal/cryptlib.h" |
0c61e299 RL |
13 | #include <openssl/rand.h> |
14 | #include "rand_lcl.h" | |
6decf943 | 15 | #include "internal/rand_int.h" |
8389ec4b | 16 | #include <stdio.h> |
0c61e299 | 17 | |
c16de9d8 | 18 | #if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \ |
8389ec4b | 19 | !defined(OPENSSL_RAND_SEED_NONE) |
c16de9d8 DMSP |
20 | # error "UEFI and VXWorks only support seeding NONE" |
21 | #endif | |
22 | ||
23 | #if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) \ | |
24 | || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \ | |
25 | || defined(OPENSSL_SYS_UEFI)) | |
0f113f3e MC |
26 | |
27 | # if defined(OPENSSL_SYS_VOS) | |
28 | ||
8389ec4b RS |
29 | # ifndef OPENSSL_RAND_SEED_OS |
30 | # error "Unsupported seeding method configured; must be os" | |
31 | # endif | |
32 | ||
33 | # if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32) | |
34 | # error "Unsupported HP-PA and IA32 at the same time." | |
35 | # endif | |
36 | # if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32) | |
37 | # error "Must have one of HP-PA or IA32" | |
38 | # endif | |
39 | ||
0f113f3e MC |
40 | /* |
41 | * The following algorithm repeatedly samples the real-time clock (RTC) to | |
42 | * generate a sequence of unpredictable data. The algorithm relies upon the | |
43 | * uneven execution speed of the code (due to factors such as cache misses, | |
44 | * interrupts, bus activity, and scheduling) and upon the rather large | |
45 | * relative difference between the speed of the clock and the rate at which | |
75e2c877 RS |
46 | * it can be read. If it is ported to an environment where execution speed |
47 | * is more constant or where the RTC ticks at a much slower rate, or the | |
48 | * clock can be read with fewer instructions, it is likely that the results | |
49 | * would be far more predictable. This should only be used for legacy | |
50 | * platforms. | |
0f113f3e | 51 | * |
c16de9d8 | 52 | * As a precaution, we assume only 2 bits of entropy per byte. |
0f113f3e | 53 | */ |
6decf943 | 54 | size_t rand_pool_acquire_entropy(RAND_POOL *pool) |
cc7399e7 | 55 | { |
0f113f3e MC |
56 | short int code; |
57 | gid_t curr_gid; | |
58 | pid_t curr_pid; | |
59 | uid_t curr_uid; | |
60 | int i, k; | |
c16de9d8 | 61 | size_t bytes_needed; |
0f113f3e MC |
62 | struct timespec ts; |
63 | unsigned char v; | |
0f113f3e MC |
64 | # ifdef OPENSSL_SYS_VOS_HPPA |
65 | long duration; | |
66 | extern void s$sleep(long *_duration, short int *_code); | |
67 | # else | |
0f113f3e MC |
68 | long long duration; |
69 | extern void s$sleep2(long long *_duration, short int *_code); | |
8389ec4b | 70 | # endif |
0f113f3e MC |
71 | |
72 | /* | |
73 | * Seed with the gid, pid, and uid, to ensure *some* variation between | |
74 | * different processes. | |
75 | */ | |
0f113f3e | 76 | curr_gid = getgid(); |
6decf943 | 77 | rand_pool_add(pool, &curr_gid, sizeof(curr_gid), 0); |
0f113f3e | 78 | curr_pid = getpid(); |
6decf943 | 79 | rand_pool_add(pool, &curr_pid, sizeof(curr_pid), 0); |
0f113f3e | 80 | curr_uid = getuid(); |
6decf943 | 81 | rand_pool_add(pool, &curr_uid, sizeof(curr_uid), 0); |
0f113f3e | 82 | |
6decf943 | 83 | bytes_needed = rand_pool_bytes_needed(pool, 2 /*entropy_per_byte*/); |
c16de9d8 DMSP |
84 | |
85 | for (i = 0; i < bytes_needed; i++) { | |
0f113f3e MC |
86 | /* |
87 | * burn some cpu; hope for interrupts, cache collisions, bus | |
88 | * interference, etc. | |
89 | */ | |
90 | for (k = 0; k < 99; k++) | |
91 | ts.tv_nsec = random(); | |
92 | ||
93 | # ifdef OPENSSL_SYS_VOS_HPPA | |
94 | /* sleep for 1/1024 of a second (976 us). */ | |
95 | duration = 1; | |
96 | s$sleep(&duration, &code); | |
97 | # else | |
0f113f3e MC |
98 | /* sleep for 1/65536 of a second (15 us). */ |
99 | duration = 1; | |
100 | s$sleep2(&duration, &code); | |
8389ec4b | 101 | # endif |
0f113f3e | 102 | |
8389ec4b | 103 | /* Get wall clock time, take 8 bits. */ |
0f113f3e | 104 | clock_gettime(CLOCK_REALTIME, &ts); |
8389ec4b | 105 | v = (unsigned char)(ts.tv_nsec & 0xFF); |
6decf943 | 106 | rand_pool_add(pool, arg, &v, sizeof(v) , 2); |
0f113f3e | 107 | } |
6decf943 | 108 | return rand_pool_entropy_available(pool); |
cc7399e7 | 109 | } |
8389ec4b | 110 | |
810ef917 | 111 | # else |
8389ec4b RS |
112 | |
113 | # if defined(OPENSSL_RAND_SEED_EGD) && \ | |
114 | (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD)) | |
115 | # error "Seeding uses EGD but EGD is turned off or no device given" | |
0f113f3e MC |
116 | # endif |
117 | ||
8389ec4b RS |
118 | # if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM) |
119 | # error "Seeding uses urandom but DEVRANDOM is not configured" | |
120 | # endif | |
0f113f3e | 121 | |
8389ec4b | 122 | # if defined(OPENSSL_RAND_SEED_OS) |
72960279 | 123 | # if !defined(DEVRANDOM) |
8389ec4b | 124 | # error "OS seeding requires DEVRANDOM to be configured" |
0f113f3e | 125 | # endif |
72960279 KR |
126 | # define OPENSSL_RAND_SEED_DEVRANDOM |
127 | # if defined(__GLIBC__) && defined(__GLIBC_PREREQ) | |
128 | # if __GLIBC_PREREQ(2, 25) | |
129 | # define OPENSSL_RAND_SEED_GETRANDOM | |
130 | # endif | |
131 | # endif | |
132 | # endif | |
133 | ||
134 | # ifdef OPENSSL_RAND_SEED_GETRANDOM | |
135 | # include <sys/random.h> | |
8389ec4b | 136 | # endif |
0f113f3e | 137 | |
8389ec4b RS |
138 | # if defined(OPENSSL_RAND_SEED_LIBRANDOM) |
139 | # error "librandom not (yet) supported" | |
140 | # endif | |
0f113f3e | 141 | |
75e2c877 | 142 | /* |
c16de9d8 DMSP |
143 | * Try the various seeding methods in turn, exit when successful. |
144 | * | |
145 | * TODO(DRBG): If more than one entropy source is available, is it | |
146 | * preferable to stop as soon as enough entropy has been collected | |
147 | * (as favored by @rsalz) or should one rather be defensive and add | |
148 | * more entropy than requested and/or from different sources? | |
149 | * | |
150 | * Currently, the user can select multiple entropy sources in the | |
151 | * configure step, yet in practice only the first available source | |
152 | * will be used. A more flexible solution has been requested, but | |
153 | * currently it is not clear how this can be achieved without | |
154 | * overengineering the problem. There are many parameters which | |
155 | * could be taken into account when selecting the order and amount | |
156 | * of input from the different entropy sources (trust, quality, | |
157 | * possibility of blocking). | |
75e2c877 | 158 | */ |
6decf943 | 159 | size_t rand_pool_acquire_entropy(RAND_POOL *pool) |
8389ec4b RS |
160 | { |
161 | # ifdef OPENSSL_RAND_SEED_NONE | |
6decf943 | 162 | return rand_pool_entropy_available(pool); |
8389ec4b | 163 | # else |
c16de9d8 DMSP |
164 | size_t bytes_needed; |
165 | size_t entropy_available = 0; | |
166 | unsigned char *buffer; | |
0f113f3e | 167 | |
75e2c877 | 168 | # ifdef OPENSSL_RAND_SEED_GETRANDOM |
6decf943 DMSP |
169 | bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/); |
170 | buffer = rand_pool_add_begin(pool, bytes_needed); | |
c16de9d8 DMSP |
171 | if (buffer != NULL) { |
172 | size_t bytes = 0; | |
0f113f3e | 173 | |
c16de9d8 DMSP |
174 | if (getrandom(buffer, bytes_needed, 0) == (int)bytes_needed) |
175 | bytes = bytes_needed; | |
176 | ||
6decf943 | 177 | entropy_available = rand_pool_add_end(pool, bytes, 8 * bytes); |
75e2c877 | 178 | } |
c16de9d8 DMSP |
179 | if (entropy_available > 0) |
180 | return entropy_available; | |
0f113f3e MC |
181 | # endif |
182 | ||
75e2c877 | 183 | # if defined(OPENSSL_RAND_SEED_LIBRANDOM) |
8389ec4b | 184 | { |
75e2c877 | 185 | /* Not yet implemented. */ |
0f113f3e | 186 | } |
8389ec4b | 187 | # endif |
0f113f3e | 188 | |
8389ec4b | 189 | # ifdef OPENSSL_RAND_SEED_DEVRANDOM |
6decf943 | 190 | bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/); |
c16de9d8 | 191 | if (bytes_needed > 0) { |
8389ec4b RS |
192 | static const char *paths[] = { DEVRANDOM, NULL }; |
193 | FILE *fp; | |
194 | int i; | |
0f113f3e | 195 | |
8389ec4b RS |
196 | for (i = 0; paths[i] != NULL; i++) { |
197 | if ((fp = fopen(paths[i], "rb")) == NULL) | |
198 | continue; | |
199 | setbuf(fp, NULL); | |
6decf943 | 200 | buffer = rand_pool_add_begin(pool, bytes_needed); |
c16de9d8 DMSP |
201 | if (buffer != NULL) { |
202 | size_t bytes = 0; | |
203 | if (fread(buffer, 1, bytes_needed, fp) == bytes_needed) | |
204 | bytes = bytes_needed; | |
205 | ||
6decf943 | 206 | entropy_available = rand_pool_add_end(pool, bytes, 8 * bytes); |
8389ec4b | 207 | } |
75e2c877 | 208 | fclose(fp); |
c16de9d8 DMSP |
209 | if (entropy_available > 0) |
210 | return entropy_available; | |
211 | ||
6decf943 | 212 | bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/); |
8389ec4b | 213 | } |
0f113f3e | 214 | } |
8389ec4b | 215 | # endif |
0f113f3e | 216 | |
75e2c877 | 217 | # ifdef OPENSSL_RAND_SEED_RDTSC |
c16de9d8 DMSP |
218 | entropy_available = rand_acquire_entropy_from_tsc(pool); |
219 | if (entropy_available > 0) | |
220 | return entropy_available; | |
75e2c877 RS |
221 | # endif |
222 | ||
223 | # ifdef OPENSSL_RAND_SEED_RDCPU | |
c16de9d8 DMSP |
224 | entropy_available = rand_acquire_entropy_from_cpu(pool); |
225 | if (entropy_available > 0) | |
226 | return entropy_available; | |
75e2c877 RS |
227 | # endif |
228 | ||
229 | # ifdef OPENSSL_RAND_SEED_EGD | |
6decf943 | 230 | bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/); |
c16de9d8 | 231 | if (bytes_needed > 0) { |
75e2c877 RS |
232 | static const char *paths[] = { DEVRANDOM_EGD, NULL }; |
233 | int i; | |
0f113f3e | 234 | |
75e2c877 | 235 | for (i = 0; paths[i] != NULL; i++) { |
6decf943 | 236 | buffer = rand_pool_add_begin(pool, bytes_needed); |
c16de9d8 DMSP |
237 | if (buffer != NULL) { |
238 | size_t bytes = 0; | |
239 | int num = RAND_query_egd_bytes(paths[i], | |
240 | buffer, (int)bytes_needed); | |
241 | if (num == (int)bytes_needed) | |
242 | bytes = bytes_needed; | |
243 | ||
6decf943 | 244 | entropy_available = rand_pool_add_end(pool, bytes, 8 * bytes); |
75e2c877 | 245 | } |
c16de9d8 DMSP |
246 | if (entropy_available > 0) |
247 | return entropy_available; | |
8389ec4b RS |
248 | } |
249 | } | |
250 | # endif | |
0f113f3e | 251 | |
6decf943 | 252 | return rand_pool_entropy_available(pool); |
0f113f3e | 253 | # endif |
0c61e299 | 254 | } |
8389ec4b | 255 | # endif |
0c61e299 | 256 | |
57d8ff79 | 257 | #endif |