• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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