aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2014-02-05 16:05:46 -0800
committerAlex Gaynor <alex.gaynor@gmail.com>2014-02-05 16:05:46 -0800
commit6f93357f3826e321cd300c661da3e1fa2e44478b (patch)
tree33b0538cf85671bc40dbbf068ab62baadfdceb0c /cryptography
parent387424bfab02aa929127201945a5a9476abb8be6 (diff)
parentf389f84fc7bb4d20ac00c571f221185d5b4874a8 (diff)
downloadcryptography-6f93357f3826e321cd300c661da3e1fa2e44478b.tar.gz
cryptography-6f93357f3826e321cd300c661da3e1fa2e44478b.tar.bz2
cryptography-6f93357f3826e321cd300c661da3e1fa2e44478b.zip
Merge pull request #377 from reaperhulk/urandom-engine
Set default RAND engine to urandom/cryptgenrandom
Diffstat (limited to 'cryptography')
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py34
-rw-r--r--cryptography/hazmat/bindings/openssl/binding.py5
-rw-r--r--cryptography/hazmat/bindings/openssl/osrandom_engine.py198
3 files changed, 236 insertions, 1 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 74faee57..6da90cef 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -58,6 +58,40 @@ class Backend(object):
self._cipher_registry = {}
self._register_default_ciphers()
+ self.activate_osrandom_engine()
+
+ def activate_builtin_random(self):
+ # Obtain a new structural reference.
+ e = self._lib.ENGINE_get_default_RAND()
+ if e != self._ffi.NULL:
+ self._lib.ENGINE_unregister_RAND(e)
+ # Reset the RNG to use the new engine.
+ self._lib.RAND_cleanup()
+ # decrement the structural reference from get_default_RAND
+ res = self._lib.ENGINE_finish(e)
+ assert res == 1
+
+ def activate_osrandom_engine(self):
+ # Unregister and free the current engine.
+ self.activate_builtin_random()
+ # Fetches an engine by id and returns it. This creates a structural
+ # reference.
+ e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id)
+ assert e != self._ffi.NULL
+ # Initialize the engine for use. This adds a functional reference.
+ res = self._lib.ENGINE_init(e)
+ assert res == 1
+ # Set the engine as the default RAND provider.
+ res = self._lib.ENGINE_set_default_RAND(e)
+ assert res == 1
+ # Decrement the structural ref incremented by ENGINE_by_id.
+ res = self._lib.ENGINE_free(e)
+ assert res == 1
+ # Decrement the functional ref incremented by ENGINE_init.
+ res = self._lib.ENGINE_finish(e)
+ assert res == 1
+ # Reset the RNG to use the new engine.
+ self._lib.RAND_cleanup()
def openssl_version_text(self):
"""
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index 3adcc887..714ecc07 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -60,6 +60,7 @@ class Binding(object):
"nid",
"objects",
"opensslv",
+ "osrandom_engine",
"pem",
"pkcs7",
"pkcs12",
@@ -91,11 +92,13 @@ class Binding(object):
if sys.platform != "win32":
libraries = ["crypto", "ssl"]
else: # pragma: no cover
- libraries = ["libeay32", "ssleay32"]
+ libraries = ["libeay32", "ssleay32", "advapi32"]
cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
_OSX_PRE_INCLUDE, _OSX_POST_INCLUDE,
libraries)
+ res = cls.lib.Cryptography_add_osrandom_engine()
+ assert res == 1
@classmethod
def is_available(cls):
diff --git a/cryptography/hazmat/bindings/openssl/osrandom_engine.py b/cryptography/hazmat/bindings/openssl/osrandom_engine.py
new file mode 100644
index 00000000..6e7e172e
--- /dev/null
+++ b/cryptography/hazmat/bindings/openssl/osrandom_engine.py
@@ -0,0 +1,198 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+INCLUDES = """
+#ifdef _WIN32
+#include <Wincrypt.h>
+#else
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+"""
+
+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 = """
+"""
+
+WIN32_CUSTOMIZATIONS = """
+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 {
+ return 0;
+ }
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ if (hCryptProv == 0) {
+ return 0;
+ }
+
+ if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
+ ERR_put_error(ERR_LIB_RAND, 0, ERR_R_RAND_LIB, "osrandom.py", 0);
+ return 0;
+ }
+ return 1;
+}
+
+static int osrandom_finish(ENGINE *e) {
+ if (CryptReleaseContext(hCryptProv, 0)) {
+ hCryptProv = 0;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int osrandom_rand_status(void) {
+ if (hCryptProv == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+"""
+
+POSIX_CUSTOMIZATIONS = """
+static int urandom_fd = -1;
+
+static int osrandom_finish(ENGINE *e);
+
+static int osrandom_init(ENGINE *e) {
+ if (urandom_fd > -1) {
+ return 1;
+ }
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (urandom_fd > -1) {
+ int flags = fcntl(urandom_fd, F_GETFD);
+ if (flags == -1) {
+ osrandom_finish(e);
+ return 0;
+ } else if (fcntl(urandom_fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ osrandom_finish(e);
+ return 0;
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ ssize_t n;
+ while (size > 0) {
+ do {
+ n = read(urandom_fd, buffer, (size_t)size);
+ } while (n < 0 && errno == EINTR);
+ if (n <= 0) {
+ ERR_put_error(ERR_LIB_RAND, 0, ERR_R_RAND_LIB, "osrandom.py", 0);
+ return 0;
+ }
+ buffer += n;
+ size -= n;
+ }
+ return 1;
+}
+
+static int osrandom_finish(ENGINE *e) {
+ int n;
+ do {
+ n = close(urandom_fd);
+ } while (n < 0 && errno == EINTR);
+ urandom_fd = -1;
+ if (n < 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int osrandom_rand_status(void) {
+ if (urandom_fd == -1) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+"""
+
+CUSTOMIZATIONS = """
+static const char *Cryptography_osrandom_engine_id = "osrandom";
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine";
+
+#if defined(_WIN32)
+""" + WIN32_CUSTOMIZATIONS + """
+#else
+""" + POSIX_CUSTOMIZATIONS + """
+#endif
+
+/* 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,
+};
+
+int Cryptography_add_osrandom_engine(void) {
+ ENGINE *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_free(e);
+ return 0;
+ }
+ if (!ENGINE_add(e)) {
+ ENGINE_free(e);
+ return 0;
+ }
+ if (!ENGINE_free(e)) {
+ return 0;
+ }
+
+ return 1;
+}
+"""
+
+CONDITIONAL_NAMES = {}