aboutsummaryrefslogtreecommitdiffstats
path: root/src/_cffi_src/openssl
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2016-12-09 17:02:26 +0100
committerPaul Kehrer <paul.l.kehrer@gmail.com>2016-12-09 10:02:26 -0600
commit2e717761c364398dd81a3221d724369ebd74db43 (patch)
tree51c02fd876afaa098ec5628deab48a3336e28a3f /src/_cffi_src/openssl
parent0cf3690df91566c14c0c916f42af790de76e9e57 (diff)
downloadcryptography-2e717761c364398dd81a3221d724369ebd74db43.tar.gz
cryptography-2e717761c364398dd81a3221d724369ebd74db43.tar.bz2
cryptography-2e717761c364398dd81a3221d724369ebd74db43.zip
New osrandom_engine in C (#3229)
* New osrandom_engine in C Inspired by Python/random.c and the old implementation. Signed-off-by: Christian Heimes <christian@python.org> * osrandom_engine * Fix naming bug caused by search 'n replace mistake * Make it easier to override osrandom auto-detection * Add engine ctrl and backend API to get implementation from ENGINE Signed-off-by: Christian Heimes <christian@python.org> * Better test coverage, documentation, LICENSE Signed-off-by: Christian Heimes <christian@python.org> * Coverage is hard. Signed-off-by: Christian Heimes <christian@python.org> * * enable win32 check * read() returns size_t Signed-off-by: Christian Heimes <christian@python.org> * Add macOS to spelling list. Remove dead code from header file. Signed-off-by: Christian Heimes <christian@python.org> * remove CCRandomGenerateBytes path and update getentropy to work on macOS This change allows us to test all the engines in our CI: * getentropy (tested by macOS sierra) * getrandom (tested on several linux builders) * /dev/urandom (tested on FreeBSD, OS X 10.11 and below, & older linux) * CryptGenRandom (tested on windows builders) I also fixed bugs preventing compilation in the getentropy code * getentropy() returns int and is restricted to 256 bytes on macOS, too. Signed-off-by: Christian Heimes <christian@python.org> * add versionadded * Re-add import of os module * Fixes related to Alex's recent review. Signed-off-by: Christian Heimes <christian@python.org> * Add error reporting and fail for EAGAIN Add error reporting strings for various error cases. This gives us much nicer and understandable error messages. SYS_getrandom() EAGAIN is now an error. Cryptography refuses to initialize its osrandom engine when the Kernel's CPRNG hasn't been seeded yet. Signed-off-by: Christian Heimes <christian@python.org>
Diffstat (limited to 'src/_cffi_src/openssl')
-rw-r--r--src/_cffi_src/openssl/osrandom_engine.py29
-rw-r--r--src/_cffi_src/openssl/src/osrandom_engine.c576
-rw-r--r--src/_cffi_src/openssl/src/osrandom_engine.h88
3 files changed, 693 insertions, 0 deletions
diff --git a/src/_cffi_src/openssl/osrandom_engine.py b/src/_cffi_src/openssl/osrandom_engine.py
new file mode 100644
index 00000000..10c5a608
--- /dev/null
+++ b/src/_cffi_src/openssl/osrandom_engine.py
@@ -0,0 +1,29 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import os
+
+HERE = os.path.dirname(os.path.abspath(__file__))
+
+with open(os.path.join(HERE, "src/osrandom_engine.h")) as f:
+ INCLUDES = f.read()
+
+TYPES = """
+static const char *const Cryptography_osrandom_engine_name;
+static const char *const Cryptography_osrandom_engine_id;
+"""
+
+FUNCTIONS = """
+int Cryptography_add_osrandom_engine(void);
+"""
+
+MACROS = """
+"""
+
+with open(os.path.join(HERE, "src/osrandom_engine.c")) as f:
+ CUSTOMIZATIONS = f.read()
+
+CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/src/osrandom_engine.c b/src/_cffi_src/openssl/src/osrandom_engine.c
new file mode 100644
index 00000000..52f55af8
--- /dev/null
+++ b/src/_cffi_src/openssl/src/osrandom_engine.c
@@ -0,0 +1,576 @@
+/* osurandom engine
+ *
+ * Windows CryptGenRandom()
+ * macOS >= 10.12 getentropy()
+ * OpenBSD 5.6+ getentropy()
+ * other BSD getentropy() if SYS_getentropy is defined
+ * Linux 3.4.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.
+ */
+
+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 */
+
+/****************************************************************************
+ * BSD getentropy
+ */
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()";
+
+static int osrandom_init(ENGINE *e) {
+ return 1;
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ int len, res;
+ while (size > 0) {
+ /* OpenBSD and macOS restrict maximum buffer size to 256. */
+ len = size > 256 ? 256 : size;
+ res = getentropy(buffer, len);
+ 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;
+}
+
+static int osrandom_finish(ENGINE *e) {
+ return 1;
+}
+
+static int osrandom_rand_status(void) {
+ return 1;
+}
+
+static const char *osurandom_get_implementation(void) {
+ return "getentropy";
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
+
+/****************************************************************************
+ * /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 };
+
+/* return -1 on error */
+static int dev_urandom_fd(void) {
+ int fd, n, flags;
+ 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) {
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ goto error;
+ }
+ if (fstat(fd, &st)) {
+ goto error;
+ }
+ /* set CLOEXEC flag */
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ goto error;
+ } else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ goto error;
+ }
+ /* Another thread initialized the fd */
+ if (urandom_cache.fd >= 0) {
+ do {
+ n = close(fd);
+ } while (n < 0 && errno == EINTR);
+ 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) {
+ do {
+ n = close(fd);
+ } while (n < 0 && errno == EINTR);
+ }
+ 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;
+ ssize_t n;
+
+ fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+
+ while (size > 0) {
+ do {
+ n = 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, n;
+ 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;
+ do {
+ n = close(fd);
+ } while (n < 0 && errno == EINTR);
+ }
+ }
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */
+
+/****************************************************************************
+ * 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];
+ n = syscall(SYS_getrandom, dest, sizeof(dest), GRND_NONBLOCK);
+ 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;
+ case EAGAIN:
+ /* Failure: Kernel CRPNG has not been seeded yet */
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_INIT,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN,
+ __FILE__, __LINE__
+ );
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
+ 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, GRND_NONBLOCK);
+ } 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 -= n;
+ }
+ return 1;
+ }
+ return 0; /* 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;
+ }
+ return 0; /* 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";
+ }
+ return "<invalid>"; /* 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 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;
+ }
+ strncpy((char *)p, name, len);
+ return 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_EAGAIN),
+ "getrandom() initialization failed with EAGAIN. Most likely Kernel "
+ "CPRNG is not seeded yet."},
+ {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;
+}
diff --git a/src/_cffi_src/openssl/src/osrandom_engine.h b/src/_cffi_src/openssl/src/osrandom_engine.h
new file mode 100644
index 00000000..d28ebf39
--- /dev/null
+++ b/src/_cffi_src/openssl/src/osrandom_engine.h
@@ -0,0 +1,88 @@
+#ifdef _WIN32
+ #include <Wincrypt.h>
+#else
+ #include <fcntl.h>
+ #include <unistd.h>
+ /* for defined(BSD) */
+ #include <sys/param.h>
+
+ #ifdef BSD
+ /* for SYS_getentropy */
+ #include <sys/syscall.h>
+ #endif
+
+ #ifdef __APPLE__
+ #include <sys/random.h>
+ #endif
+
+ #ifdef __linux__
+ /* for SYS_getrandom */
+ #include <sys/syscall.h>
+ #ifndef GRND_NONBLOCK
+ #define GRND_NONBLOCK 0x0001
+ #endif /* GRND_NONBLOCK */
+ #endif /* __linux__ */
+#endif /* _WIN32 */
+
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM 1
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY 2
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM 3
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM 4
+
+#ifndef CRYPTOGRAPHY_OSRANDOM_ENGINE
+ #if defined(_WIN32)
+ /* Windows */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
+ #elif defined(BSD) && defined(SYS_getentropy)
+ /* OpenBSD 5.6+ or macOS 10.12+ */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
+ #elif defined(__linux__) && defined(SYS_getrandom)
+ /* Linux 3.4.17+ */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
+ #else
+ /* Keep this as last entry, fall back to /dev/urandom */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
+ #endif
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE */
+
+/* Fallbacks need /dev/urandom helper functions. */
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM || \
+ CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
+ #define CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM 1
+#endif
+
+enum {
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED = -2,
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT,
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK,
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS
+};
+
+/* engine ctrl */
+#define CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION ENGINE_CMD_BASE
+
+/* error reporting */
+static void ERR_load_Cryptography_OSRandom_strings(void);
+static void ERR_Cryptography_OSRandom_error(int function, int reason,
+ char *file, int line);
+
+#define CRYPTOGRAPHY_OSRANDOM_F_INIT 100
+#define CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES 101
+#define CRYPTOGRAPHY_OSRANDOM_F_FINISH 102
+#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD 300
+#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ 301
+
+#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT 100
+#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM 101
+#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT 102
+
+#define CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED 200
+
+#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED 300
+#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED 301
+
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED 400
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN 401
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED 402
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED 403
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT 404