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