Line data Source code
1 : /*
2 : * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * 3. Neither the name of the Institute nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : */
35 :
36 : #include <config.h>
37 : #include <roken.h>
38 :
39 : #include <rand.h>
40 : #include <randi.h>
41 :
42 : #ifndef O_BINARY
43 : #define O_BINARY 0
44 : #endif
45 :
46 : #ifdef _WIN32
47 : #include<shlobj.h>
48 : #endif
49 :
50 : /**
51 : * @page page_rand RAND - random number
52 : *
53 : * See the library functions here: @ref hcrypto_rand
54 : */
55 :
56 : static const RAND_METHOD *selected_meth = NULL;
57 : static ENGINE *selected_engine = NULL;
58 :
59 : static void
60 3566361 : init_method(void)
61 : {
62 3566361 : if (selected_meth != NULL)
63 3484034 : return;
64 : #if defined(_WIN32)
65 : selected_meth = &hc_rand_w32crypto_method;
66 : #elif defined(__APPLE__)
67 : selected_meth = &hc_rand_unix_method;
68 : #else
69 33851 : selected_meth = &hc_rand_fortuna_method;
70 : #endif
71 : }
72 :
73 : /**
74 : * Seed that random number generator. Secret material can securely be
75 : * feed into the function, they will never be returned.
76 : *
77 : * @param indata seed data
78 : * @param size length seed data
79 : *
80 : * @ingroup hcrypto_rand
81 : */
82 :
83 : void
84 0 : RAND_seed(const void *indata, size_t size)
85 : {
86 0 : init_method();
87 0 : (*selected_meth->seed)(indata, size);
88 0 : }
89 :
90 : /**
91 : * Get a random block from the random generator, can be used for key material.
92 : *
93 : * @param outdata random data
94 : * @param size length random data
95 : *
96 : * @return 1 on success, 0 on failure.
97 : *
98 : * @ingroup hcrypto_rand
99 : */
100 : int
101 3498659 : RAND_bytes(void *outdata, size_t size)
102 : {
103 3498659 : if (size == 0)
104 0 : return 1;
105 3498659 : init_method();
106 3498659 : return (*selected_meth->bytes)(outdata, size);
107 : }
108 :
109 : /**
110 : * Reset and free memory used by the random generator.
111 : *
112 : * @ingroup hcrypto_rand
113 : */
114 :
115 : void
116 0 : RAND_cleanup(void)
117 : {
118 0 : const RAND_METHOD *meth = selected_meth;
119 0 : ENGINE *engine = selected_engine;
120 :
121 0 : selected_meth = NULL;
122 0 : selected_engine = NULL;
123 :
124 0 : if (meth)
125 0 : (*meth->cleanup)();
126 0 : if (engine)
127 0 : ENGINE_finish(engine);
128 0 : }
129 :
130 : /**
131 : * Seed that random number generator. Secret material can securely be
132 : * feed into the function, they will never be returned.
133 : *
134 : * @param indata the input data.
135 : * @param size size of in data.
136 : * @param entropi entropi in data.
137 : *
138 : *
139 : * @ingroup hcrypto_rand
140 : */
141 :
142 : void
143 0 : RAND_add(const void *indata, size_t size, double entropi)
144 : {
145 0 : init_method();
146 0 : (*selected_meth->add)(indata, size, entropi);
147 0 : }
148 :
149 : /**
150 : * Get a random block from the random generator, should NOT be used for key material.
151 : *
152 : * @param outdata random data
153 : * @param size length random data
154 : *
155 : * @return 1 on success, 0 on failure.
156 : *
157 : * @ingroup hcrypto_rand
158 : */
159 :
160 : int
161 0 : RAND_pseudo_bytes(void *outdata, size_t size)
162 : {
163 0 : init_method();
164 0 : return (*selected_meth->pseudorand)(outdata, size);
165 : }
166 :
167 : /**
168 : * Return status of the random generator
169 : *
170 : * @return 1 if the random generator can deliver random data.
171 : *
172 : * @ingroup hcrypto_rand
173 : */
174 :
175 : int
176 67702 : RAND_status(void)
177 : {
178 67702 : init_method();
179 67702 : return (*selected_meth->status)();
180 : }
181 :
182 : /**
183 : * Set the default random method.
184 : *
185 : * @param meth set the new default method.
186 : *
187 : * @return 1 on success.
188 : *
189 : * @ingroup hcrypto_rand
190 : */
191 :
192 : int
193 0 : RAND_set_rand_method(const RAND_METHOD *meth)
194 : {
195 0 : const RAND_METHOD *old = selected_meth;
196 0 : selected_meth = meth;
197 0 : if (old)
198 0 : (*old->cleanup)();
199 0 : if (selected_engine) {
200 0 : ENGINE_finish(selected_engine);
201 0 : selected_engine = NULL;
202 : }
203 0 : return 1;
204 : }
205 :
206 : /**
207 : * Get the default random method.
208 : *
209 : * @return Returns a RAND_METHOD
210 : *
211 : * @ingroup hcrypto_rand
212 : */
213 :
214 : const RAND_METHOD *
215 0 : RAND_get_rand_method(void)
216 : {
217 0 : init_method();
218 0 : return selected_meth;
219 : }
220 :
221 : /**
222 : * Set the default random method from engine.
223 : *
224 : * @param engine use engine, if NULL is passed it, old method and engine is cleared.
225 : *
226 : * @return 1 on success, 0 on failure.
227 : *
228 : * @ingroup hcrypto_rand
229 : */
230 :
231 : int
232 0 : RAND_set_rand_engine(ENGINE *engine)
233 : {
234 0 : const RAND_METHOD *meth, *old = selected_meth;
235 :
236 0 : if (engine) {
237 0 : ENGINE_up_ref(engine);
238 0 : meth = ENGINE_get_RAND(engine);
239 0 : if (meth == NULL) {
240 0 : ENGINE_finish(engine);
241 0 : return 0;
242 : }
243 : } else {
244 0 : meth = NULL;
245 : }
246 :
247 0 : if (old)
248 0 : (*old->cleanup)();
249 :
250 0 : if (selected_engine)
251 0 : ENGINE_finish(selected_engine);
252 :
253 0 : selected_engine = engine;
254 0 : selected_meth = meth;
255 :
256 0 : return 1;
257 : }
258 :
259 : #define RAND_FILE_SIZE 1024
260 :
261 : /**
262 : * Load a a file and feed it into RAND_seed().
263 : *
264 : * @param filename name of file to read.
265 : * @param size minimum size to read.
266 : *
267 : * @return Returns the number of seed bytes loaded (0 indicates failure)
268 : *
269 : * @ingroup hcrypto_rand
270 : */
271 :
272 : int
273 0 : RAND_load_file(const char *filename, size_t size)
274 : {
275 0 : unsigned char buf[128];
276 0 : size_t len;
277 0 : ssize_t slen;
278 0 : int fd;
279 :
280 0 : fd = open(filename, O_RDONLY | O_BINARY, 0600);
281 0 : if (fd < 0)
282 0 : return 0;
283 0 : rk_cloexec(fd);
284 0 : len = 0;
285 0 : while(len < size) {
286 0 : slen = read(fd, buf, sizeof(buf));
287 0 : if (slen <= 0)
288 0 : break;
289 0 : RAND_seed(buf, slen);
290 0 : len += slen;
291 : }
292 0 : close(fd);
293 :
294 0 : return len ? 1 : 0;
295 : }
296 :
297 : /**
298 : * Write of random numbers to a file to store for later initiation with RAND_load_file().
299 : *
300 : * @param filename name of file to write.
301 : *
302 : * @return 1 on success and non-one on failure.
303 : * @ingroup hcrypto_rand
304 : */
305 :
306 : int
307 0 : RAND_write_file(const char *filename)
308 : {
309 0 : unsigned char buf[128];
310 0 : size_t len;
311 0 : int res = 0, fd;
312 :
313 0 : fd = open(filename, O_WRONLY | O_CREAT | O_BINARY, 0600);
314 0 : if (fd < 0)
315 0 : return 0;
316 0 : rk_cloexec(fd);
317 :
318 0 : len = 0;
319 0 : while(len < RAND_FILE_SIZE) {
320 0 : res = RAND_bytes(buf, sizeof(buf));
321 0 : if (res != 1)
322 0 : break;
323 0 : if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
324 0 : res = 0;
325 0 : break;
326 : }
327 0 : len += sizeof(buf);
328 : }
329 :
330 0 : close(fd);
331 :
332 0 : return res;
333 : }
334 :
335 : /**
336 : * Return the default random state filename for a user to use for
337 : * RAND_load_file(), and RAND_write_file().
338 : *
339 : * @param filename buffer to hold file name.
340 : * @param size size of buffer filename.
341 : *
342 : * @return the buffer filename or NULL on failure.
343 : *
344 : * @ingroup hcrypto_rand
345 : */
346 :
347 : const char *
348 33851 : RAND_file_name(char *filename, size_t size)
349 : {
350 33851 : const char *e = NULL;
351 33851 : int pathp = 0, ret;
352 :
353 33851 : e = secure_getenv("RANDFILE");
354 33851 : if (e == NULL)
355 33851 : e = secure_getenv("HOME");
356 33851 : if (e)
357 33851 : pathp = 1;
358 :
359 : #ifndef _WIN32
360 : /*
361 : * Here we really want to call getpwuid(getuid()) but this will
362 : * cause recursive lookups if the nss library uses
363 : * gssapi/krb5/hcrypto to authenticate to the ldap servers.
364 : *
365 : * So at least return the unix /dev/random if we have one
366 : */
367 33851 : if (e == NULL) {
368 0 : int fd;
369 :
370 0 : fd = _hc_unix_device_fd(O_RDONLY, &e);
371 0 : if (fd >= 0)
372 0 : close(fd);
373 : }
374 : #else /* Win32 */
375 :
376 : if (e == NULL) {
377 : char profile[MAX_PATH];
378 :
379 : if (SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
380 : SHGFP_TYPE_CURRENT, profile) == S_OK) {
381 : ret = snprintf(filename, size, "%s\\.rnd", profile);
382 :
383 : if (ret > 0 && ret < size)
384 : return filename;
385 : }
386 : }
387 :
388 : #endif
389 :
390 33851 : if (e == NULL)
391 0 : return NULL;
392 :
393 33851 : if (pathp)
394 33851 : ret = snprintf(filename, size, "%s/.rnd", e);
395 : else
396 0 : ret = snprintf(filename, size, "%s", e);
397 :
398 33851 : if (ret <= 0 || ret >= size)
399 0 : return NULL;
400 :
401 32582 : return filename;
402 : }
|