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