aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c
diff options
context:
space:
mode:
authortorkve <torkve@yandex-team.ru>2022-02-10 16:48:23 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:48:23 +0300
commitf9cfbeee51d5849127bb58793a2edcdfd7bb91bb (patch)
treef7c863cfcc3f1cb6de7f77e11fec2ae60868c8fb /contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c
parent5eefa17021221fd267f1dd5f9d63d2493d131a8a (diff)
downloadydb-f9cfbeee51d5849127bb58793a2edcdfd7bb91bb.tar.gz
Restoring authorship annotation for <torkve@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c')
-rw-r--r--contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c1320
1 files changed, 660 insertions, 660 deletions
diff --git a/contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c b/contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c
index a84857b86d..fb765b1c02 100644
--- a/contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c
+++ b/contrib/python/cryptography/_cffi_src/openssl/src/osrandom_engine.c
@@ -1,660 +1,660 @@
-/* osurandom engine
- *
- * Windows CryptGenRandom()
- * macOS >= 10.12 getentropy()
- * OpenBSD 5.6+ getentropy()
- * other BSD getentropy() if SYS_getentropy is defined
- * Linux 3.17+ getrandom() with fallback to /dev/urandom
- * other /dev/urandom with cached fd
- *
- * The /dev/urandom, getrandom and getentropy code is derived from Python's
- * Python/random.c, written by Antoine Pitrou and Victor Stinner.
- *
- * Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
- */
-
-#ifdef __linux__
-#include <poll.h>
-#endif
-
-#if CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE
-/* OpenSSL has ENGINE support and is older than 1.1.1d (the first version that
- * properly implements fork safety in its RNG) so build the engine. */
-static const char *Cryptography_osrandom_engine_id = "osrandom";
-
-/****************************************************************************
- * Windows
- */
-#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
-static const char *Cryptography_osrandom_engine_name = "osrandom_engine CryptGenRandom()";
-static HCRYPTPROV hCryptProv = 0;
-
-static int osrandom_init(ENGINE *e) {
- if (hCryptProv != 0) {
- return 1;
- }
- if (CryptAcquireContext(&hCryptProv, NULL, NULL,
- PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- return 1;
- } else {
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_INIT,
- CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT,
- __FILE__, __LINE__
- );
- return 0;
- }
-}
-
-static int osrandom_rand_bytes(unsigned char *buffer, int size) {
- if (hCryptProv == 0) {
- return 0;
- }
-
- if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
- CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM,
- __FILE__, __LINE__
- );
- return 0;
- }
- return 1;
-}
-
-static int osrandom_finish(ENGINE *e) {
- if (CryptReleaseContext(hCryptProv, 0)) {
- hCryptProv = 0;
- return 1;
- } else {
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_FINISH,
- CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT,
- __FILE__, __LINE__
- );
- return 0;
- }
-}
-
-static int osrandom_rand_status(void) {
- return hCryptProv != 0;
-}
-
-static const char *osurandom_get_implementation(void) {
- return "CryptGenRandom";
-}
-
-#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM */
-
-/****************************************************************************
- * /dev/urandom helpers for all non-BSD Unix platforms
- */
-#ifdef CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM
-
-static struct {
- int fd;
- dev_t st_dev;
- ino_t st_ino;
-} urandom_cache = { -1 };
-
-static int open_cloexec(const char *path) {
- int open_flags = O_RDONLY;
-#ifdef O_CLOEXEC
- open_flags |= O_CLOEXEC;
-#endif
-
- int fd = open(path, open_flags);
- if (fd == -1) {
- return -1;
- }
-
-#ifndef O_CLOEXEC
- int flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- return -1;
- }
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
- return -1;
- }
-#endif
- return fd;
-}
-
-#ifdef __linux__
-/* On Linux, we open("/dev/random") and use poll() to wait until it's readable
- * before we read from /dev/urandom, this ensures that we don't read from
- * /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on
- * other platforms because they don't have the same _bug_ as Linux does with
- * /dev/urandom and early boot. */
-static int wait_on_devrandom(void) {
- struct pollfd pfd = {};
- int ret = 0;
- int random_fd = open_cloexec("/dev/random");
- if (random_fd < 0) {
- return -1;
- }
- pfd.fd = random_fd;
- pfd.events = POLLIN;
- pfd.revents = 0;
- do {
- ret = poll(&pfd, 1, -1);
- } while (ret < 0 && (errno == EINTR || errno == EAGAIN));
- close(random_fd);
- return ret;
-}
-#endif
-
-/* return -1 on error */
-static int dev_urandom_fd(void) {
- int fd = -1;
- struct stat st;
-
- /* Check that fd still points to the correct device */
- if (urandom_cache.fd >= 0) {
- if (fstat(urandom_cache.fd, &st)
- || st.st_dev != urandom_cache.st_dev
- || st.st_ino != urandom_cache.st_ino) {
- /* Somebody replaced our FD. Invalidate our cache but don't
- * close the fd. */
- urandom_cache.fd = -1;
- }
- }
- if (urandom_cache.fd < 0) {
-#ifdef __linux__
- if (wait_on_devrandom() < 0) {
- goto error;
- }
-#endif
-
- fd = open_cloexec("/dev/urandom");
- if (fd < 0) {
- goto error;
- }
- if (fstat(fd, &st)) {
- goto error;
- }
- /* Another thread initialized the fd */
- if (urandom_cache.fd >= 0) {
- close(fd);
- return urandom_cache.fd;
- }
- urandom_cache.st_dev = st.st_dev;
- urandom_cache.st_ino = st.st_ino;
- urandom_cache.fd = fd;
- }
- return urandom_cache.fd;
-
- error:
- if (fd != -1) {
- close(fd);
- }
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD,
- CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED,
- __FILE__, __LINE__
- );
- return -1;
-}
-
-static int dev_urandom_read(unsigned char *buffer, int size) {
- int fd;
- int n;
-
- fd = dev_urandom_fd();
- if (fd < 0) {
- return 0;
- }
-
- while (size > 0) {
- do {
- n = (int)read(fd, buffer, (size_t)size);
- } while (n < 0 && errno == EINTR);
-
- if (n <= 0) {
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ,
- CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED,
- __FILE__, __LINE__
- );
- return 0;
- }
- buffer += n;
- size -= n;
- }
- return 1;
-}
-
-static void dev_urandom_close(void) {
- if (urandom_cache.fd >= 0) {
- int fd;
- struct stat st;
-
- if (fstat(urandom_cache.fd, &st)
- && st.st_dev == urandom_cache.st_dev
- && st.st_ino == urandom_cache.st_ino) {
- fd = urandom_cache.fd;
- urandom_cache.fd = -1;
- close(fd);
- }
- }
-}
-#endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */
-
-/****************************************************************************
- * BSD getentropy
- */
-#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
-static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()";
-
-static int getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_NOT_INIT;
-
-static int osrandom_init(ENGINE *e) {
-#if !defined(__APPLE__)
- getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
-#else
- if (__builtin_available(macOS 10.12, *)) {
- getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
- } else {
- getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK;
- int fd = dev_urandom_fd();
- if (fd < 0) {
- return 0;
- }
- }
-#endif
- return 1;
-}
-
-static int osrandom_rand_bytes(unsigned char *buffer, int size) {
- int len;
- int res;
-
- switch(getentropy_works) {
-#if defined(__APPLE__)
- case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
- return dev_urandom_read(buffer, size);
-#endif
- case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
- while (size > 0) {
- /* OpenBSD and macOS restrict maximum buffer size to 256. */
- len = size > 256 ? 256 : size;
-/* on mac, availability is already checked using `__builtin_available` above */
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
- res = getentropy(buffer, (size_t)len);
-#pragma clang diagnostic pop
- if (res < 0) {
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
- CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED,
- __FILE__, __LINE__
- );
- return 0;
- }
- buffer += len;
- size -= len;
- }
- return 1;
- }
- __builtin_unreachable();
-}
-
-static int osrandom_finish(ENGINE *e) {
- return 1;
-}
-
-static int osrandom_rand_status(void) {
- return 1;
-}
-
-static const char *osurandom_get_implementation(void) {
- switch(getentropy_works) {
- case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
- return "/dev/urandom";
- case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
- return "getentropy";
- }
- __builtin_unreachable();
-}
-#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
-
-/****************************************************************************
- * Linux getrandom engine with fallback to dev_urandom
- */
-
-#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
-static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()";
-
-static int getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT;
-
-static int osrandom_init(ENGINE *e) {
- /* We try to detect working getrandom until we succeed. */
- if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) {
- long n;
- char dest[1];
- /* if the kernel CSPRNG is not initialized this will block */
- n = syscall(SYS_getrandom, dest, sizeof(dest), 0);
- if (n == sizeof(dest)) {
- getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS;
- } else {
- int e = errno;
- switch(e) {
- case ENOSYS:
- /* Fallback: Kernel does not support the syscall. */
- getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
- break;
- case EPERM:
- /* Fallback: seccomp prevents syscall */
- getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
- break;
- default:
- /* EINTR cannot occur for buflen < 256. */
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_INIT,
- CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED,
- "errno", e
- );
- getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
- break;
- }
- }
- }
-
- /* fallback to dev urandom */
- if (getrandom_works == CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK) {
- int fd = dev_urandom_fd();
- if (fd < 0) {
- return 0;
- }
- }
- return 1;
-}
-
-static int osrandom_rand_bytes(unsigned char *buffer, int size) {
- long n;
-
- switch(getrandom_works) {
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
- CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED,
- __FILE__, __LINE__
- );
- return 0;
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
- CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT,
- __FILE__, __LINE__
- );
- return 0;
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
- return dev_urandom_read(buffer, size);
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
- while (size > 0) {
- do {
- n = syscall(SYS_getrandom, buffer, size, 0);
- } while (n < 0 && errno == EINTR);
-
- if (n <= 0) {
- ERR_Cryptography_OSRandom_error(
- CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
- CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED,
- __FILE__, __LINE__
- );
- return 0;
- }
- buffer += n;
- size -= (int)n;
- }
- return 1;
- }
- __builtin_unreachable();
-}
-
-static int osrandom_finish(ENGINE *e) {
- dev_urandom_close();
- return 1;
-}
-
-static int osrandom_rand_status(void) {
- switch(getrandom_works) {
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
- return 0;
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
- return 0;
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
- return urandom_cache.fd >= 0;
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
- return 1;
- }
- __builtin_unreachable();
-}
-
-static const char *osurandom_get_implementation(void) {
- switch(getrandom_works) {
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
- return "<failed>";
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
- return "<not initialized>";
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
- return "/dev/urandom";
- case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
- return "getrandom";
- }
- __builtin_unreachable();
-}
-#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
-
-/****************************************************************************
- * dev_urandom engine for all remaining platforms
- */
-
-#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
-static const char *Cryptography_osrandom_engine_name = "osrandom_engine /dev/urandom";
-
-static int osrandom_init(ENGINE *e) {
- int fd = dev_urandom_fd();
- if (fd < 0) {
- return 0;
- }
- return 1;
-}
-
-static int osrandom_rand_bytes(unsigned char *buffer, int size) {
- return dev_urandom_read(buffer, size);
-}
-
-static int osrandom_finish(ENGINE *e) {
- dev_urandom_close();
- return 1;
-}
-
-static int osrandom_rand_status(void) {
- return urandom_cache.fd >= 0;
-}
-
-static const char *osurandom_get_implementation(void) {
- return "/dev/urandom";
-}
-#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM */
-
-/****************************************************************************
- * ENGINE boiler plate
- */
-
-/* This replicates the behavior of the OpenSSL FIPS RNG, which returns a
- -1 in the event that there is an error when calling RAND_pseudo_bytes. */
-static int osrandom_pseudo_rand_bytes(unsigned char *buffer, int size) {
- int res = osrandom_rand_bytes(buffer, size);
- if (res == 0) {
- return -1;
- } else {
- return res;
- }
-}
-
-static RAND_METHOD osrandom_rand = {
- NULL,
- osrandom_rand_bytes,
- NULL,
- NULL,
- osrandom_pseudo_rand_bytes,
- osrandom_rand_status,
-};
-
-static const ENGINE_CMD_DEFN osrandom_cmd_defns[] = {
- {CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION,
- "get_implementation",
- "Get CPRNG implementation.",
- ENGINE_CMD_FLAG_NO_INPUT},
- {0, NULL, NULL, 0}
-};
-
-static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) {
- const char *name;
- size_t len;
-
- switch (cmd) {
- case CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION:
- /* i: buffer size, p: char* buffer */
- name = osurandom_get_implementation();
- len = strlen(name);
- if ((p == NULL) && (i == 0)) {
- /* return required buffer len */
- return (int)len;
- }
- if ((p == NULL) || i < 0 || ((size_t)i <= len)) {
- /* no buffer or buffer too small */
- ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT);
- return 0;
- }
- strcpy((char *)p, name);
- return (int)len;
- default:
- ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
- return 0;
- }
-}
-
-/* error reporting */
-#define ERR_FUNC(func) ERR_PACK(0, func, 0)
-#define ERR_REASON(reason) ERR_PACK(0, 0, reason)
-
-static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_lib_name[] = {
- {0, "osrandom_engine"},
- {0, NULL}
-};
-
-static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_funcs[] = {
- {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_INIT),
- "osrandom_init"},
- {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES),
- "osrandom_rand_bytes"},
- {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_FINISH),
- "osrandom_finish"},
- {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD),
- "dev_urandom_fd"},
- {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ),
- "dev_urandom_read"},
- {0, NULL}
-};
-
-static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_reasons[] = {
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT),
- "CryptAcquireContext() failed."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM),
- "CryptGenRandom() failed."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT),
- "CryptReleaseContext() failed."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED),
- "getentropy() failed"},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED),
- "open('/dev/urandom') failed."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED),
- "Reading from /dev/urandom fd failed."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED),
- "getrandom() initialization failed."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED),
- "getrandom() initialization failed with unexpected errno."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED),
- "getrandom() syscall failed."},
- {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT),
- "getrandom() engine was not properly initialized."},
- {0, NULL}
-};
-
-static int Cryptography_OSRandom_lib_error_code = 0;
-
-static void ERR_load_Cryptography_OSRandom_strings(void)
-{
- if (Cryptography_OSRandom_lib_error_code == 0) {
- Cryptography_OSRandom_lib_error_code = ERR_get_next_error_library();
- ERR_load_strings(Cryptography_OSRandom_lib_error_code,
- CRYPTOGRAPHY_OSRANDOM_lib_name);
- ERR_load_strings(Cryptography_OSRandom_lib_error_code,
- CRYPTOGRAPHY_OSRANDOM_str_funcs);
- ERR_load_strings(Cryptography_OSRandom_lib_error_code,
- CRYPTOGRAPHY_OSRANDOM_str_reasons);
- }
-}
-
-static void ERR_Cryptography_OSRandom_error(int function, int reason,
- char *file, int line)
-{
- ERR_PUT_error(Cryptography_OSRandom_lib_error_code, function, reason,
- file, line);
-}
-
-/* Returns 1 if successfully added, 2 if engine has previously been added,
- and 0 for error. */
-int Cryptography_add_osrandom_engine(void) {
- ENGINE *e;
-
- ERR_load_Cryptography_OSRandom_strings();
-
- e = ENGINE_by_id(Cryptography_osrandom_engine_id);
- if (e != NULL) {
- ENGINE_free(e);
- return 2;
- } else {
- ERR_clear_error();
- }
-
- e = ENGINE_new();
- if (e == NULL) {
- return 0;
- }
- if (!ENGINE_set_id(e, Cryptography_osrandom_engine_id) ||
- !ENGINE_set_name(e, Cryptography_osrandom_engine_name) ||
- !ENGINE_set_RAND(e, &osrandom_rand) ||
- !ENGINE_set_init_function(e, osrandom_init) ||
- !ENGINE_set_finish_function(e, osrandom_finish) ||
- !ENGINE_set_cmd_defns(e, osrandom_cmd_defns) ||
- !ENGINE_set_ctrl_function(e, osrandom_ctrl)) {
- ENGINE_free(e);
- return 0;
- }
- if (!ENGINE_add(e)) {
- ENGINE_free(e);
- return 0;
- }
- if (!ENGINE_free(e)) {
- return 0;
- }
-
- return 1;
-}
-
-#else
-/* If OpenSSL has no ENGINE support then we don't want
- * to compile the osrandom engine, but we do need some
- * placeholders */
-static const char *Cryptography_osrandom_engine_id = "no-engine-support";
-static const char *Cryptography_osrandom_engine_name = "osrandom_engine disabled";
-
-int Cryptography_add_osrandom_engine(void) {
- return 0;
-}
-
-#endif
+/* osurandom engine
+ *
+ * Windows CryptGenRandom()
+ * macOS >= 10.12 getentropy()
+ * OpenBSD 5.6+ getentropy()
+ * other BSD getentropy() if SYS_getentropy is defined
+ * Linux 3.17+ getrandom() with fallback to /dev/urandom
+ * other /dev/urandom with cached fd
+ *
+ * The /dev/urandom, getrandom and getentropy code is derived from Python's
+ * Python/random.c, written by Antoine Pitrou and Victor Stinner.
+ *
+ * Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
+ */
+
+#ifdef __linux__
+#include <poll.h>
+#endif
+
+#if CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE
+/* OpenSSL has ENGINE support and is older than 1.1.1d (the first version that
+ * properly implements fork safety in its RNG) so build the engine. */
+static const char *Cryptography_osrandom_engine_id = "osrandom";
+
+/****************************************************************************
+ * Windows
+ */
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine CryptGenRandom()";
+static HCRYPTPROV hCryptProv = 0;
+
+static int osrandom_init(ENGINE *e) {
+ if (hCryptProv != 0) {
+ return 1;
+ }
+ if (CryptAcquireContext(&hCryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ return 1;
+ } else {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_INIT,
+ CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ if (hCryptProv == 0) {
+ return 0;
+ }
+
+ if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ return 1;
+}
+
+static int osrandom_finish(ENGINE *e) {
+ if (CryptReleaseContext(hCryptProv, 0)) {
+ hCryptProv = 0;
+ return 1;
+ } else {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_FINISH,
+ CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+}
+
+static int osrandom_rand_status(void) {
+ return hCryptProv != 0;
+}
+
+static const char *osurandom_get_implementation(void) {
+ return "CryptGenRandom";
+}
+
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM */
+
+/****************************************************************************
+ * /dev/urandom helpers for all non-BSD Unix platforms
+ */
+#ifdef CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM
+
+static struct {
+ int fd;
+ dev_t st_dev;
+ ino_t st_ino;
+} urandom_cache = { -1 };
+
+static int open_cloexec(const char *path) {
+ int open_flags = O_RDONLY;
+#ifdef O_CLOEXEC
+ open_flags |= O_CLOEXEC;
+#endif
+
+ int fd = open(path, open_flags);
+ if (fd == -1) {
+ return -1;
+ }
+
+#ifndef O_CLOEXEC
+ int flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ return -1;
+ }
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ return -1;
+ }
+#endif
+ return fd;
+}
+
+#ifdef __linux__
+/* On Linux, we open("/dev/random") and use poll() to wait until it's readable
+ * before we read from /dev/urandom, this ensures that we don't read from
+ * /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on
+ * other platforms because they don't have the same _bug_ as Linux does with
+ * /dev/urandom and early boot. */
+static int wait_on_devrandom(void) {
+ struct pollfd pfd = {};
+ int ret = 0;
+ int random_fd = open_cloexec("/dev/random");
+ if (random_fd < 0) {
+ return -1;
+ }
+ pfd.fd = random_fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ do {
+ ret = poll(&pfd, 1, -1);
+ } while (ret < 0 && (errno == EINTR || errno == EAGAIN));
+ close(random_fd);
+ return ret;
+}
+#endif
+
+/* return -1 on error */
+static int dev_urandom_fd(void) {
+ int fd = -1;
+ struct stat st;
+
+ /* Check that fd still points to the correct device */
+ if (urandom_cache.fd >= 0) {
+ if (fstat(urandom_cache.fd, &st)
+ || st.st_dev != urandom_cache.st_dev
+ || st.st_ino != urandom_cache.st_ino) {
+ /* Somebody replaced our FD. Invalidate our cache but don't
+ * close the fd. */
+ urandom_cache.fd = -1;
+ }
+ }
+ if (urandom_cache.fd < 0) {
+#ifdef __linux__
+ if (wait_on_devrandom() < 0) {
+ goto error;
+ }
+#endif
+
+ fd = open_cloexec("/dev/urandom");
+ if (fd < 0) {
+ goto error;
+ }
+ if (fstat(fd, &st)) {
+ goto error;
+ }
+ /* Another thread initialized the fd */
+ if (urandom_cache.fd >= 0) {
+ close(fd);
+ return urandom_cache.fd;
+ }
+ urandom_cache.st_dev = st.st_dev;
+ urandom_cache.st_ino = st.st_ino;
+ urandom_cache.fd = fd;
+ }
+ return urandom_cache.fd;
+
+ error:
+ if (fd != -1) {
+ close(fd);
+ }
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD,
+ CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED,
+ __FILE__, __LINE__
+ );
+ return -1;
+}
+
+static int dev_urandom_read(unsigned char *buffer, int size) {
+ int fd;
+ int n;
+
+ fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+
+ while (size > 0) {
+ do {
+ n = (int)read(fd, buffer, (size_t)size);
+ } while (n < 0 && errno == EINTR);
+
+ if (n <= 0) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ,
+ CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ buffer += n;
+ size -= n;
+ }
+ return 1;
+}
+
+static void dev_urandom_close(void) {
+ if (urandom_cache.fd >= 0) {
+ int fd;
+ struct stat st;
+
+ if (fstat(urandom_cache.fd, &st)
+ && st.st_dev == urandom_cache.st_dev
+ && st.st_ino == urandom_cache.st_ino) {
+ fd = urandom_cache.fd;
+ urandom_cache.fd = -1;
+ close(fd);
+ }
+ }
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */
+
+/****************************************************************************
+ * BSD getentropy
+ */
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()";
+
+static int getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_NOT_INIT;
+
+static int osrandom_init(ENGINE *e) {
+#if !defined(__APPLE__)
+ getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
+#else
+ if (__builtin_available(macOS 10.12, *)) {
+ getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
+ } else {
+ getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK;
+ int fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+ }
+#endif
+ return 1;
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ int len;
+ int res;
+
+ switch(getentropy_works) {
+#if defined(__APPLE__)
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
+ return dev_urandom_read(buffer, size);
+#endif
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
+ while (size > 0) {
+ /* OpenBSD and macOS restrict maximum buffer size to 256. */
+ len = size > 256 ? 256 : size;
+/* on mac, availability is already checked using `__builtin_available` above */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+ res = getentropy(buffer, (size_t)len);
+#pragma clang diagnostic pop
+ if (res < 0) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ buffer += len;
+ size -= len;
+ }
+ return 1;
+ }
+ __builtin_unreachable();
+}
+
+static int osrandom_finish(ENGINE *e) {
+ return 1;
+}
+
+static int osrandom_rand_status(void) {
+ return 1;
+}
+
+static const char *osurandom_get_implementation(void) {
+ switch(getentropy_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
+ return "/dev/urandom";
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
+ return "getentropy";
+ }
+ __builtin_unreachable();
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
+
+/****************************************************************************
+ * Linux getrandom engine with fallback to dev_urandom
+ */
+
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()";
+
+static int getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT;
+
+static int osrandom_init(ENGINE *e) {
+ /* We try to detect working getrandom until we succeed. */
+ if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) {
+ long n;
+ char dest[1];
+ /* if the kernel CSPRNG is not initialized this will block */
+ n = syscall(SYS_getrandom, dest, sizeof(dest), 0);
+ if (n == sizeof(dest)) {
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS;
+ } else {
+ int e = errno;
+ switch(e) {
+ case ENOSYS:
+ /* Fallback: Kernel does not support the syscall. */
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
+ break;
+ case EPERM:
+ /* Fallback: seccomp prevents syscall */
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
+ break;
+ default:
+ /* EINTR cannot occur for buflen < 256. */
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_INIT,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED,
+ "errno", e
+ );
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
+ break;
+ }
+ }
+ }
+
+ /* fallback to dev urandom */
+ if (getrandom_works == CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK) {
+ int fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ long n;
+
+ switch(getrandom_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT,
+ __FILE__, __LINE__
+ );
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
+ return dev_urandom_read(buffer, size);
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
+ while (size > 0) {
+ do {
+ n = syscall(SYS_getrandom, buffer, size, 0);
+ } while (n < 0 && errno == EINTR);
+
+ if (n <= 0) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ buffer += n;
+ size -= (int)n;
+ }
+ return 1;
+ }
+ __builtin_unreachable();
+}
+
+static int osrandom_finish(ENGINE *e) {
+ dev_urandom_close();
+ return 1;
+}
+
+static int osrandom_rand_status(void) {
+ switch(getrandom_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
+ return urandom_cache.fd >= 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
+ return 1;
+ }
+ __builtin_unreachable();
+}
+
+static const char *osurandom_get_implementation(void) {
+ switch(getrandom_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
+ return "<failed>";
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
+ return "<not initialized>";
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
+ return "/dev/urandom";
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
+ return "getrandom";
+ }
+ __builtin_unreachable();
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
+
+/****************************************************************************
+ * dev_urandom engine for all remaining platforms
+ */
+
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine /dev/urandom";
+
+static int osrandom_init(ENGINE *e) {
+ int fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+ return 1;
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ return dev_urandom_read(buffer, size);
+}
+
+static int osrandom_finish(ENGINE *e) {
+ dev_urandom_close();
+ return 1;
+}
+
+static int osrandom_rand_status(void) {
+ return urandom_cache.fd >= 0;
+}
+
+static const char *osurandom_get_implementation(void) {
+ return "/dev/urandom";
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM */
+
+/****************************************************************************
+ * ENGINE boiler plate
+ */
+
+/* This replicates the behavior of the OpenSSL FIPS RNG, which returns a
+ -1 in the event that there is an error when calling RAND_pseudo_bytes. */
+static int osrandom_pseudo_rand_bytes(unsigned char *buffer, int size) {
+ int res = osrandom_rand_bytes(buffer, size);
+ if (res == 0) {
+ return -1;
+ } else {
+ return res;
+ }
+}
+
+static RAND_METHOD osrandom_rand = {
+ NULL,
+ osrandom_rand_bytes,
+ NULL,
+ NULL,
+ osrandom_pseudo_rand_bytes,
+ osrandom_rand_status,
+};
+
+static const ENGINE_CMD_DEFN osrandom_cmd_defns[] = {
+ {CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION,
+ "get_implementation",
+ "Get CPRNG implementation.",
+ ENGINE_CMD_FLAG_NO_INPUT},
+ {0, NULL, NULL, 0}
+};
+
+static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) {
+ const char *name;
+ size_t len;
+
+ switch (cmd) {
+ case CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION:
+ /* i: buffer size, p: char* buffer */
+ name = osurandom_get_implementation();
+ len = strlen(name);
+ if ((p == NULL) && (i == 0)) {
+ /* return required buffer len */
+ return (int)len;
+ }
+ if ((p == NULL) || i < 0 || ((size_t)i <= len)) {
+ /* no buffer or buffer too small */
+ ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT);
+ return 0;
+ }
+ strcpy((char *)p, name);
+ return (int)len;
+ default:
+ ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
+ return 0;
+ }
+}
+
+/* error reporting */
+#define ERR_FUNC(func) ERR_PACK(0, func, 0)
+#define ERR_REASON(reason) ERR_PACK(0, 0, reason)
+
+static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_lib_name[] = {
+ {0, "osrandom_engine"},
+ {0, NULL}
+};
+
+static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_funcs[] = {
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_INIT),
+ "osrandom_init"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES),
+ "osrandom_rand_bytes"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_FINISH),
+ "osrandom_finish"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD),
+ "dev_urandom_fd"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ),
+ "dev_urandom_read"},
+ {0, NULL}
+};
+
+static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_reasons[] = {
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT),
+ "CryptAcquireContext() failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM),
+ "CryptGenRandom() failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT),
+ "CryptReleaseContext() failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED),
+ "getentropy() failed"},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED),
+ "open('/dev/urandom') failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED),
+ "Reading from /dev/urandom fd failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED),
+ "getrandom() initialization failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED),
+ "getrandom() initialization failed with unexpected errno."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED),
+ "getrandom() syscall failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT),
+ "getrandom() engine was not properly initialized."},
+ {0, NULL}
+};
+
+static int Cryptography_OSRandom_lib_error_code = 0;
+
+static void ERR_load_Cryptography_OSRandom_strings(void)
+{
+ if (Cryptography_OSRandom_lib_error_code == 0) {
+ Cryptography_OSRandom_lib_error_code = ERR_get_next_error_library();
+ ERR_load_strings(Cryptography_OSRandom_lib_error_code,
+ CRYPTOGRAPHY_OSRANDOM_lib_name);
+ ERR_load_strings(Cryptography_OSRandom_lib_error_code,
+ CRYPTOGRAPHY_OSRANDOM_str_funcs);
+ ERR_load_strings(Cryptography_OSRandom_lib_error_code,
+ CRYPTOGRAPHY_OSRANDOM_str_reasons);
+ }
+}
+
+static void ERR_Cryptography_OSRandom_error(int function, int reason,
+ char *file, int line)
+{
+ ERR_PUT_error(Cryptography_OSRandom_lib_error_code, function, reason,
+ file, line);
+}
+
+/* Returns 1 if successfully added, 2 if engine has previously been added,
+ and 0 for error. */
+int Cryptography_add_osrandom_engine(void) {
+ ENGINE *e;
+
+ ERR_load_Cryptography_OSRandom_strings();
+
+ e = ENGINE_by_id(Cryptography_osrandom_engine_id);
+ if (e != NULL) {
+ ENGINE_free(e);
+ return 2;
+ } else {
+ ERR_clear_error();
+ }
+
+ e = ENGINE_new();
+ if (e == NULL) {
+ return 0;
+ }
+ if (!ENGINE_set_id(e, Cryptography_osrandom_engine_id) ||
+ !ENGINE_set_name(e, Cryptography_osrandom_engine_name) ||
+ !ENGINE_set_RAND(e, &osrandom_rand) ||
+ !ENGINE_set_init_function(e, osrandom_init) ||
+ !ENGINE_set_finish_function(e, osrandom_finish) ||
+ !ENGINE_set_cmd_defns(e, osrandom_cmd_defns) ||
+ !ENGINE_set_ctrl_function(e, osrandom_ctrl)) {
+ ENGINE_free(e);
+ return 0;
+ }
+ if (!ENGINE_add(e)) {
+ ENGINE_free(e);
+ return 0;
+ }
+ if (!ENGINE_free(e)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+#else
+/* If OpenSSL has no ENGINE support then we don't want
+ * to compile the osrandom engine, but we do need some
+ * placeholders */
+static const char *Cryptography_osrandom_engine_id = "no-engine-support";
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine disabled";
+
+int Cryptography_add_osrandom_engine(void) {
+ return 0;
+}
+
+#endif