1 /* osurandom engine
2 *
3 * Windows CryptGenRandom()
4 * macOS >= 10.12 getentropy()
5 * OpenBSD 5.6+ getentropy()
6 * other BSD getentropy() if SYS_getentropy is defined
7 * Linux 3.17+ getrandom() with fallback to /dev/urandom
8 * other /dev/urandom with cached fd
9 *
10 * The /dev/urandom, getrandom and getentropy code is derived from Python's
11 * Python/random.c, written by Antoine Pitrou and Victor Stinner.
12 *
13 * Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
14 */
15
16 #ifdef __linux__
17 #include <poll.h>
18 #endif
19
20 static const char *Cryptography_osrandom_engine_id = "osrandom";
21
22 /****************************************************************************
23 * Windows
24 */
25 #if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
26 static const char *Cryptography_osrandom_engine_name = "osrandom_engine CryptGenRandom()";
27 static HCRYPTPROV hCryptProv = 0;
28
osrandom_init(ENGINE * e)29 static int osrandom_init(ENGINE *e) {
30 if (hCryptProv != 0) {
31 return 1;
32 }
33 if (CryptAcquireContext(&hCryptProv, NULL, NULL,
34 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
35 return 1;
36 } else {
37 ERR_Cryptography_OSRandom_error(
38 CRYPTOGRAPHY_OSRANDOM_F_INIT,
39 CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT,
40 __FILE__, __LINE__
41 );
42 return 0;
43 }
44 }
45
osrandom_rand_bytes(unsigned char * buffer,int size)46 static int osrandom_rand_bytes(unsigned char *buffer, int size) {
47 if (hCryptProv == 0) {
48 return 0;
49 }
50
51 if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
52 ERR_Cryptography_OSRandom_error(
53 CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
54 CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM,
55 __FILE__, __LINE__
56 );
57 return 0;
58 }
59 return 1;
60 }
61
osrandom_finish(ENGINE * e)62 static int osrandom_finish(ENGINE *e) {
63 if (CryptReleaseContext(hCryptProv, 0)) {
64 hCryptProv = 0;
65 return 1;
66 } else {
67 ERR_Cryptography_OSRandom_error(
68 CRYPTOGRAPHY_OSRANDOM_F_FINISH,
69 CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT,
70 __FILE__, __LINE__
71 );
72 return 0;
73 }
74 }
75
osrandom_rand_status(void)76 static int osrandom_rand_status(void) {
77 return hCryptProv != 0;
78 }
79
osurandom_get_implementation(void)80 static const char *osurandom_get_implementation(void) {
81 return "CryptGenRandom";
82 }
83
84 #endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM */
85
86 /****************************************************************************
87 * /dev/urandom helpers for all non-BSD Unix platforms
88 */
89 #ifdef CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM
90
91 static struct {
92 int fd;
93 dev_t st_dev;
94 ino_t st_ino;
95 } urandom_cache = { -1 };
96
set_cloexec(int fd)97 static int set_cloexec(int fd) {
98 int flags = fcntl(fd, F_GETFD);
99 if (flags == -1) {
100 return -1;
101 }
102 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
103 return -1;
104 }
105 return 0;
106 }
107
108 #ifdef __linux__
109 /* On Linux, we open("/dev/random") and use poll() to wait until it's readable
110 * before we read from /dev/urandom, this ensures that we don't read from
111 * /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on
112 * other platforms because they don't have the same _bug_ as Linux does with
113 * /dev/urandom and early boot. */
wait_on_devrandom(void)114 static int wait_on_devrandom(void) {
115 struct pollfd pfd = {};
116 int ret = 0;
117 int random_fd = open("/dev/random", O_RDONLY);
118 if (random_fd < 0) {
119 return -1;
120 }
121 if (set_cloexec(random_fd) < 0) {
122 return -1;
123 }
124 pfd.fd = random_fd;
125 pfd.events = POLLIN;
126 pfd.revents = 0;
127 do {
128 ret = poll(&pfd, 1, -1);
129 } while (ret < 0 && (errno == EINTR || errno == EAGAIN));
130 close(random_fd);
131 return ret;
132 }
133 #endif
134
135 /* return -1 on error */
dev_urandom_fd(void)136 static int dev_urandom_fd(void) {
137 int fd = -1;
138 struct stat st;
139
140 /* Check that fd still points to the correct device */
141 if (urandom_cache.fd >= 0) {
142 if (fstat(urandom_cache.fd, &st)
143 || st.st_dev != urandom_cache.st_dev
144 || st.st_ino != urandom_cache.st_ino) {
145 /* Somebody replaced our FD. Invalidate our cache but don't
146 * close the fd. */
147 urandom_cache.fd = -1;
148 }
149 }
150 if (urandom_cache.fd < 0) {
151 #ifdef __linux__
152 if (wait_on_devrandom() < 0) {
153 goto error;
154 }
155 #endif
156
157 fd = open("/dev/urandom", O_RDONLY);
158 if (fd < 0) {
159 goto error;
160 }
161 if (set_cloexec(fd) < 0) {
162 goto error;
163 }
164 if (fstat(fd, &st)) {
165 goto error;
166 }
167 /* Another thread initialized the fd */
168 if (urandom_cache.fd >= 0) {
169 close(fd);
170 return urandom_cache.fd;
171 }
172 urandom_cache.st_dev = st.st_dev;
173 urandom_cache.st_ino = st.st_ino;
174 urandom_cache.fd = fd;
175 }
176 return urandom_cache.fd;
177
178 error:
179 if (fd != -1) {
180 close(fd);
181 }
182 ERR_Cryptography_OSRandom_error(
183 CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD,
184 CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED,
185 __FILE__, __LINE__
186 );
187 return -1;
188 }
189
dev_urandom_read(unsigned char * buffer,int size)190 static int dev_urandom_read(unsigned char *buffer, int size) {
191 int fd;
192 int n;
193
194 fd = dev_urandom_fd();
195 if (fd < 0) {
196 return 0;
197 }
198
199 while (size > 0) {
200 do {
201 n = (int)read(fd, buffer, (size_t)size);
202 } while (n < 0 && errno == EINTR);
203
204 if (n <= 0) {
205 ERR_Cryptography_OSRandom_error(
206 CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ,
207 CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED,
208 __FILE__, __LINE__
209 );
210 return 0;
211 }
212 buffer += n;
213 size -= n;
214 }
215 return 1;
216 }
217
dev_urandom_close(void)218 static void dev_urandom_close(void) {
219 if (urandom_cache.fd >= 0) {
220 int fd;
221 struct stat st;
222
223 if (fstat(urandom_cache.fd, &st)
224 && st.st_dev == urandom_cache.st_dev
225 && st.st_ino == urandom_cache.st_ino) {
226 fd = urandom_cache.fd;
227 urandom_cache.fd = -1;
228 close(fd);
229 }
230 }
231 }
232 #endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */
233
234 /****************************************************************************
235 * BSD getentropy
236 */
237 #if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
238 static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()";
239
240 static int getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_NOT_INIT;
241
osrandom_init(ENGINE * e)242 static int osrandom_init(ENGINE *e) {
243 #if !defined(__APPLE__)
244 getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
245 #else
246 if (&getentropy != NULL) {
247 getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
248 } else {
249 getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK;
250 int fd = dev_urandom_fd();
251 if (fd < 0) {
252 return 0;
253 }
254 }
255 #endif
256 return 1;
257 }
258
osrandom_rand_bytes(unsigned char * buffer,int size)259 static int osrandom_rand_bytes(unsigned char *buffer, int size) {
260 int len;
261 int res;
262
263 switch(getentropy_works) {
264 #if defined(__APPLE__)
265 case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
266 return dev_urandom_read(buffer, size);
267 #endif
268 case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
269 while (size > 0) {
270 /* OpenBSD and macOS restrict maximum buffer size to 256. */
271 len = size > 256 ? 256 : size;
272 res = getentropy(buffer, (size_t)len);
273 if (res < 0) {
274 ERR_Cryptography_OSRandom_error(
275 CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
276 CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED,
277 __FILE__, __LINE__
278 );
279 return 0;
280 }
281 buffer += len;
282 size -= len;
283 }
284 return 1;
285 }
286 __builtin_unreachable();
287 }
288
osrandom_finish(ENGINE * e)289 static int osrandom_finish(ENGINE *e) {
290 return 1;
291 }
292
osrandom_rand_status(void)293 static int osrandom_rand_status(void) {
294 return 1;
295 }
296
osurandom_get_implementation(void)297 static const char *osurandom_get_implementation(void) {
298 switch(getentropy_works) {
299 case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
300 return "/dev/urandom";
301 case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
302 return "getentropy";
303 }
304 __builtin_unreachable();
305 }
306 #endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
307
308 /****************************************************************************
309 * Linux getrandom engine with fallback to dev_urandom
310 */
311
312 #if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
313 static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()";
314
315 static int getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT;
316
osrandom_init(ENGINE * e)317 static int osrandom_init(ENGINE *e) {
318 /* We try to detect working getrandom until we succeed. */
319 if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) {
320 long n;
321 char dest[1];
322 /* if the kernel CSPRNG is not initialized this will block */
323 n = syscall(SYS_getrandom, dest, sizeof(dest), 0);
324 if (n == sizeof(dest)) {
325 getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS;
326 } else {
327 int e = errno;
328 switch(e) {
329 case ENOSYS:
330 /* Fallback: Kernel does not support the syscall. */
331 getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
332 break;
333 case EPERM:
334 /* Fallback: seccomp prevents syscall */
335 getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
336 break;
337 default:
338 /* EINTR cannot occur for buflen < 256. */
339 ERR_Cryptography_OSRandom_error(
340 CRYPTOGRAPHY_OSRANDOM_F_INIT,
341 CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED,
342 "errno", e
343 );
344 getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
345 break;
346 }
347 }
348 }
349
350 /* fallback to dev urandom */
351 if (getrandom_works == CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK) {
352 int fd = dev_urandom_fd();
353 if (fd < 0) {
354 return 0;
355 }
356 }
357 return 1;
358 }
359
osrandom_rand_bytes(unsigned char * buffer,int size)360 static int osrandom_rand_bytes(unsigned char *buffer, int size) {
361 long n;
362
363 switch(getrandom_works) {
364 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
365 ERR_Cryptography_OSRandom_error(
366 CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
367 CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED,
368 __FILE__, __LINE__
369 );
370 return 0;
371 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
372 ERR_Cryptography_OSRandom_error(
373 CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
374 CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT,
375 __FILE__, __LINE__
376 );
377 return 0;
378 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
379 return dev_urandom_read(buffer, size);
380 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
381 while (size > 0) {
382 do {
383 n = syscall(SYS_getrandom, buffer, size, 0);
384 } while (n < 0 && errno == EINTR);
385
386 if (n <= 0) {
387 ERR_Cryptography_OSRandom_error(
388 CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
389 CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED,
390 __FILE__, __LINE__
391 );
392 return 0;
393 }
394 buffer += n;
395 size -= (int)n;
396 }
397 return 1;
398 }
399 __builtin_unreachable();
400 }
401
osrandom_finish(ENGINE * e)402 static int osrandom_finish(ENGINE *e) {
403 dev_urandom_close();
404 return 1;
405 }
406
osrandom_rand_status(void)407 static int osrandom_rand_status(void) {
408 switch(getrandom_works) {
409 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
410 return 0;
411 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
412 return 0;
413 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
414 return urandom_cache.fd >= 0;
415 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
416 return 1;
417 }
418 __builtin_unreachable();
419 }
420
osurandom_get_implementation(void)421 static const char *osurandom_get_implementation(void) {
422 switch(getrandom_works) {
423 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
424 return "<failed>";
425 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
426 return "<not initialized>";
427 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
428 return "/dev/urandom";
429 case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
430 return "getrandom";
431 }
432 __builtin_unreachable();
433 }
434 #endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
435
436 /****************************************************************************
437 * dev_urandom engine for all remaining platforms
438 */
439
440 #if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
441 static const char *Cryptography_osrandom_engine_name = "osrandom_engine /dev/urandom";
442
osrandom_init(ENGINE * e)443 static int osrandom_init(ENGINE *e) {
444 int fd = dev_urandom_fd();
445 if (fd < 0) {
446 return 0;
447 }
448 return 1;
449 }
450
osrandom_rand_bytes(unsigned char * buffer,int size)451 static int osrandom_rand_bytes(unsigned char *buffer, int size) {
452 return dev_urandom_read(buffer, size);
453 }
454
osrandom_finish(ENGINE * e)455 static int osrandom_finish(ENGINE *e) {
456 dev_urandom_close();
457 return 1;
458 }
459
osrandom_rand_status(void)460 static int osrandom_rand_status(void) {
461 return urandom_cache.fd >= 0;
462 }
463
osurandom_get_implementation(void)464 static const char *osurandom_get_implementation(void) {
465 return "/dev/urandom";
466 }
467 #endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM */
468
469 /****************************************************************************
470 * ENGINE boiler plate
471 */
472
473 /* This replicates the behavior of the OpenSSL FIPS RNG, which returns a
474 -1 in the event that there is an error when calling RAND_pseudo_bytes. */
osrandom_pseudo_rand_bytes(unsigned char * buffer,int size)475 static int osrandom_pseudo_rand_bytes(unsigned char *buffer, int size) {
476 int res = osrandom_rand_bytes(buffer, size);
477 if (res == 0) {
478 return -1;
479 } else {
480 return res;
481 }
482 }
483
484 static RAND_METHOD osrandom_rand = {
485 NULL,
486 osrandom_rand_bytes,
487 NULL,
488 NULL,
489 osrandom_pseudo_rand_bytes,
490 osrandom_rand_status,
491 };
492
493 static const ENGINE_CMD_DEFN osrandom_cmd_defns[] = {
494 {CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION,
495 "get_implementation",
496 "Get CPRNG implementation.",
497 ENGINE_CMD_FLAG_NO_INPUT},
498 {0, NULL, NULL, 0}
499 };
500
osrandom_ctrl(ENGINE * e,int cmd,long i,void * p,void (* f)(void))501 static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) {
502 const char *name;
503 size_t len;
504
505 switch (cmd) {
506 case CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION:
507 /* i: buffer size, p: char* buffer */
508 name = osurandom_get_implementation();
509 len = strlen(name);
510 if ((p == NULL) && (i == 0)) {
511 /* return required buffer len */
512 return (int)len;
513 }
514 if ((p == NULL) || i < 0 || ((size_t)i <= len)) {
515 /* no buffer or buffer too small */
516 ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT);
517 return 0;
518 }
519 strncpy((char *)p, name, len);
520 return (int)len;
521 default:
522 ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
523 return 0;
524 }
525 }
526
527 /* error reporting */
528 #define ERR_FUNC(func) ERR_PACK(0, func, 0)
529 #define ERR_REASON(reason) ERR_PACK(0, 0, reason)
530
531 static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_lib_name[] = {
532 {0, "osrandom_engine"},
533 {0, NULL}
534 };
535
536 static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_funcs[] = {
537 {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_INIT),
538 "osrandom_init"},
539 {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES),
540 "osrandom_rand_bytes"},
541 {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_FINISH),
542 "osrandom_finish"},
543 {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD),
544 "dev_urandom_fd"},
545 {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ),
546 "dev_urandom_read"},
547 {0, NULL}
548 };
549
550 static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_reasons[] = {
551 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT),
552 "CryptAcquireContext() failed."},
553 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM),
554 "CryptGenRandom() failed."},
555 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT),
556 "CryptReleaseContext() failed."},
557 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED),
558 "getentropy() failed"},
559 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED),
560 "open('/dev/urandom') failed."},
561 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED),
562 "Reading from /dev/urandom fd failed."},
563 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED),
564 "getrandom() initialization failed."},
565 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED),
566 "getrandom() initialization failed with unexpected errno."},
567 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED),
568 "getrandom() syscall failed."},
569 {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT),
570 "getrandom() engine was not properly initialized."},
571 {0, NULL}
572 };
573
574 static int Cryptography_OSRandom_lib_error_code = 0;
575
ERR_load_Cryptography_OSRandom_strings(void)576 static void ERR_load_Cryptography_OSRandom_strings(void)
577 {
578 if (Cryptography_OSRandom_lib_error_code == 0) {
579 Cryptography_OSRandom_lib_error_code = ERR_get_next_error_library();
580 ERR_load_strings(Cryptography_OSRandom_lib_error_code,
581 CRYPTOGRAPHY_OSRANDOM_lib_name);
582 ERR_load_strings(Cryptography_OSRandom_lib_error_code,
583 CRYPTOGRAPHY_OSRANDOM_str_funcs);
584 ERR_load_strings(Cryptography_OSRandom_lib_error_code,
585 CRYPTOGRAPHY_OSRANDOM_str_reasons);
586 }
587 }
588
ERR_Cryptography_OSRandom_error(int function,int reason,char * file,int line)589 static void ERR_Cryptography_OSRandom_error(int function, int reason,
590 char *file, int line)
591 {
592 ERR_PUT_error(Cryptography_OSRandom_lib_error_code, function, reason,
593 file, line);
594 }
595
596 /* Returns 1 if successfully added, 2 if engine has previously been added,
597 and 0 for error. */
Cryptography_add_osrandom_engine(void)598 int Cryptography_add_osrandom_engine(void) {
599 ENGINE *e;
600
601 ERR_load_Cryptography_OSRandom_strings();
602
603 e = ENGINE_by_id(Cryptography_osrandom_engine_id);
604 if (e != NULL) {
605 ENGINE_free(e);
606 return 2;
607 } else {
608 ERR_clear_error();
609 }
610
611 e = ENGINE_new();
612 if (e == NULL) {
613 return 0;
614 }
615 if (!ENGINE_set_id(e, Cryptography_osrandom_engine_id) ||
616 !ENGINE_set_name(e, Cryptography_osrandom_engine_name) ||
617 !ENGINE_set_RAND(e, &osrandom_rand) ||
618 !ENGINE_set_init_function(e, osrandom_init) ||
619 !ENGINE_set_finish_function(e, osrandom_finish) ||
620 !ENGINE_set_cmd_defns(e, osrandom_cmd_defns) ||
621 !ENGINE_set_ctrl_function(e, osrandom_ctrl)) {
622 ENGINE_free(e);
623 return 0;
624 }
625 if (!ENGINE_add(e)) {
626 ENGINE_free(e);
627 return 0;
628 }
629 if (!ENGINE_free(e)) {
630 return 0;
631 }
632
633 return 1;
634 }
635