From 026168cc80c964b237ebd65a20c05679acd48332 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 29 Dec 2013 19:51:17 -0600 Subject: add urandom engine and set it as default RAND method. This is a proposed solution to the OpenSSL fork problem. --- cryptography/hazmat/backends/openssl/backend.py | 10 ++ .../hazmat/backends/openssl/urand_engine.py | 155 +++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 cryptography/hazmat/backends/openssl/urand_engine.py diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 6231aadb..d6a77640 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -93,6 +93,7 @@ class Backend(object): "rand", "rsa", "ssl", + "urand_engine", "x509", "x509name", "x509v3", @@ -170,6 +171,15 @@ class Backend(object): cls.lib.OpenSSL_add_all_algorithms() cls.lib.SSL_load_error_strings() + res = cls.lib.Cryptography_add_urandom_engine() + assert res == 1 + e = cls.lib.ENGINE_by_id("urandom") + assert e != cls.ffi.NULL + res = cls.lib.ENGINE_init(e) + assert res == 1 + res = cls.lib.ENGINE_set_default_RAND(e) + assert res == 1 + def openssl_version_text(self): """ Friendly string name of linked OpenSSL. diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py new file mode 100644 index 00000000..479bbb2c --- /dev/null +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -0,0 +1,155 @@ +# 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 +#else +#include +#include +#endif +""" + +TYPES = """ +""" + +FUNCTIONS = """ +int Cryptography_add_urandom_engine(void); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +static const char *urandom_engine_id= "urandom"; +static const char *urandom_engine_name = "urandom engine"; + +#ifndef _WIN32 +static int urandom_fd; + +static int urandom_rand_bytes(unsigned char *buffer, int size) { + ssize_t n; + while (0 < size) { + do { + n = read(urandom_fd, buffer, (size_t)size); + } while (n < 0 && errno == EINTR); + if (n <= 0) { + return 0; + break; + } + buffer += n; + size -= n; + } + return 1; +} + +static int urandom_rand_status(void) { + return 1; +} + +static int urandom_init(ENGINE *e) { + urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd > 0) { + return 1; + } else { + printf("crap"); + return 0; + } +} + +static int urandom_finish(ENGINE *e) { + int n; + do { + n = close(urandom_fd); + } while (n < 0 && errno == EINTR); + if (n < 0) { + return 0; + } else { + return 1; + } +} +#endif + +#ifdef _WIN32 +/* This handle is never explicitly released. Instead, the operating + system will release it when the process terminates. */ +static HCRYPTPROV hCryptProv = 0; + +static int urandom_init(ENGINE *e) { + /* Acquire context */ + if (CryptAcquireContext(&hCryptProv, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + return 1; + } else { + return 0; + } +} + +static int urandom_rand_bytes(unsigned char *buffer, int size) { + size_t chunk; + + if (hCryptProv == 0) { + return 0; + } + + while (size > 0) { + chunk = size > INT_MAX ? INT_MAX : size; + if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer)) { + return 0; + } + buffer += chunk; + size -= chunk; + } + return 1; +} + +static int urandom_finish(ENGINE *e) { + return 1; +} + +static int urandom_rand_status(void) { + return 1; +} +#endif /* MS_WINDOWS */ + +static RAND_METHOD urandom_rand = { + NULL, + urandom_rand_bytes, + NULL, + NULL, + urandom_rand_bytes, + urandom_rand_status, +}; + +int Cryptography_add_urandom_engine(void) { + ENGINE *e = ENGINE_new(); + if(!ENGINE_set_id(e, urandom_engine_id) || + !ENGINE_set_name(e, urandom_engine_name) || + !ENGINE_set_RAND(e, &urandom_rand) || + !ENGINE_set_init_function(e, urandom_init) || + !ENGINE_set_finish_function(e, urandom_finish)) { + return 0; + } + if (!ENGINE_add(e)) { + ENGINE_free(e); + return 0; + } + if (!ENGINE_free(e)) { + return 0; + } + + return 1; +} +""" + +CONDITIONAL_NAMES = {} -- cgit v1.2.3 From 541c72021bfae49712a16069c44a32737e4b283b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 29 Dec 2013 23:23:03 -0600 Subject: allow the backend to register/unregister the engine via methods --- cryptography/hazmat/backends/openssl/backend.py | 37 +++++++++++++++++++--- .../hazmat/backends/openssl/urand_engine.py | 2 +- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index d6a77640..0f134e52 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -107,6 +107,7 @@ class Backend(object): self._cipher_registry = {} self._register_default_ciphers() + self.register_urandom_engine() @classmethod def _ensure_ffi_initialized(cls): @@ -171,14 +172,42 @@ class Backend(object): cls.lib.OpenSSL_add_all_algorithms() cls.lib.SSL_load_error_strings() + # Add the urandom engine to the engine list res = cls.lib.Cryptography_add_urandom_engine() assert res == 1 - e = cls.lib.ENGINE_by_id("urandom") - assert e != cls.ffi.NULL - res = cls.lib.ENGINE_init(e) + + def unregister_urandom_engine(self): + e = self.lib.ENGINE_get_default_RAND() + if e != self.ffi.NULL: + name = self.lib.ENGINE_get_name(e) + assert name != self.ffi.NULL + if self.ffi.string(name) == "urandom_engine": + self.lib.ENGINE_unregister_RAND(e) + res = self.lib.ENGINE_free(e) + assert res == 1 + self.lib.RAND_cleanup() + + def register_urandom_engine(self): + current_rand = self.lib.ENGINE_get_default_RAND() + if current_rand != self.ffi.NULL: + name = self.lib.ENGINE_get_name(current_rand) + assert name != self.ffi.NULL + if self.ffi.string(name) == "urandom_engine": + res = self.lib.ENGINE_finish(current_rand) + assert res == 1 + return + + e = self.lib.ENGINE_by_id("urandom") + assert e != self.ffi.NULL + res = self.lib.ENGINE_init(e) + assert res == 1 + res = self.lib.ENGINE_set_default_RAND(e) + assert res == 1 + res = self.lib.ENGINE_finish(e) assert res == 1 - res = cls.lib.ENGINE_set_default_RAND(e) + res = self.lib.ENGINE_free(e) assert res == 1 + self.lib.RAND_cleanup() def openssl_version_text(self): """ diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index 479bbb2c..0a86af3e 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -32,7 +32,7 @@ MACROS = """ CUSTOMIZATIONS = """ static const char *urandom_engine_id= "urandom"; -static const char *urandom_engine_name = "urandom engine"; +static const char *urandom_engine_name = "urandom_engine"; #ifndef _WIN32 static int urandom_fd; -- cgit v1.2.3 From e646369697f9de02b904c6492cc523305108a244 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 30 Dec 2013 08:28:18 -0600 Subject: add urandom engine register/unregister tests also rename some variables in the urandom engine for easier comparison --- cryptography/hazmat/backends/openssl/backend.py | 32 ++++++------ .../hazmat/backends/openssl/urand_engine.py | 11 ++-- tests/hazmat/backends/test_openssl.py | 58 ++++++++++++++++++++++ 3 files changed, 81 insertions(+), 20 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 0f134e52..a61e7b05 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -181,10 +181,11 @@ class Backend(object): if e != self.ffi.NULL: name = self.lib.ENGINE_get_name(e) assert name != self.ffi.NULL - if self.ffi.string(name) == "urandom_engine": + if name == self.lib.Cryptography_urandom_engine_name: self.lib.ENGINE_unregister_RAND(e) res = self.lib.ENGINE_free(e) assert res == 1 + # this resets the RNG to use the new engine self.lib.RAND_cleanup() def register_urandom_engine(self): @@ -192,22 +193,23 @@ class Backend(object): if current_rand != self.ffi.NULL: name = self.lib.ENGINE_get_name(current_rand) assert name != self.ffi.NULL - if self.ffi.string(name) == "urandom_engine": + if name == self.lib.Cryptography_urandom_engine_name: + # urand is already the current default RAND res = self.lib.ENGINE_finish(current_rand) assert res == 1 - return - - e = self.lib.ENGINE_by_id("urandom") - assert e != self.ffi.NULL - res = self.lib.ENGINE_init(e) - assert res == 1 - res = self.lib.ENGINE_set_default_RAND(e) - assert res == 1 - res = self.lib.ENGINE_finish(e) - assert res == 1 - res = self.lib.ENGINE_free(e) - assert res == 1 - self.lib.RAND_cleanup() + else: + e = self.lib.ENGINE_by_id(self.lib.Cryptography_urandom_engine_id) + assert e != self.ffi.NULL + res = self.lib.ENGINE_init(e) + assert res == 1 + res = self.lib.ENGINE_set_default_RAND(e) + assert res == 1 + res = self.lib.ENGINE_finish(e) + assert res == 1 + res = self.lib.ENGINE_free(e) + assert res == 1 + # this resets the RNG to use the new engine + self.lib.RAND_cleanup() def openssl_version_text(self): """ diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index 0a86af3e..67ebe272 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -21,6 +21,8 @@ INCLUDES = """ """ TYPES = """ +static const char *const Cryptography_urandom_engine_name; +static const char *const Cryptography_urandom_engine_id; """ FUNCTIONS = """ @@ -31,8 +33,8 @@ MACROS = """ """ CUSTOMIZATIONS = """ -static const char *urandom_engine_id= "urandom"; -static const char *urandom_engine_name = "urandom_engine"; +static const char *Cryptography_urandom_engine_id= "urandom"; +static const char *Cryptography_urandom_engine_name = "urandom_engine"; #ifndef _WIN32 static int urandom_fd; @@ -86,7 +88,6 @@ static int urandom_finish(ENGINE *e) { static HCRYPTPROV hCryptProv = 0; static int urandom_init(ENGINE *e) { - /* Acquire context */ if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { return 1; @@ -133,8 +134,8 @@ static RAND_METHOD urandom_rand = { int Cryptography_add_urandom_engine(void) { ENGINE *e = ENGINE_new(); - if(!ENGINE_set_id(e, urandom_engine_id) || - !ENGINE_set_name(e, urandom_engine_name) || + if(!ENGINE_set_id(e, Cryptography_urandom_engine_id) || + !ENGINE_set_name(e, Cryptography_urandom_engine_name) || !ENGINE_set_RAND(e, &urandom_rand) || !ENGINE_set_init_function(e, urandom_init) || !ENGINE_set_finish_function(e, urandom_finish)) { diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 543a05fe..4dd74c35 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -97,3 +97,61 @@ class TestOpenSSL(object): backend.lib.EVP_F_EVP_DECRYPTFINAL_EX, 0 ) + + # This test is not in the next class because to check if it's really + # default we don't want to run the setup_method before it + def test_urandom_engine_is_default(self): + e = backend.lib.ENGINE_get_default_RAND() + name = backend.lib.ENGINE_get_name(e) + assert name == backend.lib.Cryptography_urandom_engine_name + res = backend.lib.ENGINE_free(e) + assert res == 1 + + +class TestOpenSSLRandomEngine(object): + def setup_method(self, method): + # we need to reset state to being default. backend is a shared global + # for all these tests. + backend.register_urandom_engine() + pass + + def test_register_urandom_already_default(self): + e = backend.lib.ENGINE_get_default_RAND() + name = backend.lib.ENGINE_get_name(e) + assert name == backend.lib.Cryptography_urandom_engine_name + res = backend.lib.ENGINE_free(e) + assert res == 1 + backend.register_urandom_engine() + e = backend.lib.ENGINE_get_default_RAND() + name = backend.lib.ENGINE_get_name(e) + assert name == backend.lib.Cryptography_urandom_engine_name + res = backend.lib.ENGINE_free(e) + assert res == 1 + + def test_unregister_urandom_engine_already_unregistered(self): + backend.unregister_urandom_engine() + e = backend.lib.ENGINE_get_default_RAND() + assert e == backend.ffi.NULL + backend.unregister_urandom_engine() + e = backend.lib.ENGINE_get_default_RAND() + assert e == backend.ffi.NULL + + def test_unregister_urandom_engine(self): + e = backend.lib.ENGINE_get_default_RAND() + assert e != backend.ffi.NULL + name = backend.lib.ENGINE_get_name(e) + assert name == backend.lib.Cryptography_urandom_engine_name + backend.unregister_urandom_engine() + e = backend.lib.ENGINE_get_default_RAND() + assert e == backend.ffi.NULL + + def test_register_urandom_not_default(self): + backend.unregister_urandom_engine() + e = backend.lib.ENGINE_get_default_RAND() + assert e == backend.ffi.NULL + backend.register_urandom_engine() + e = backend.lib.ENGINE_get_default_RAND() + name = backend.lib.ENGINE_get_name(e) + assert name == backend.lib.Cryptography_urandom_engine_name + res = backend.lib.ENGINE_free(e) + assert res == 1 -- cgit v1.2.3 From 698f22fb6c83f1d2710dfa2d21960e140fce7380 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 30 Dec 2013 10:50:45 -0600 Subject: fix fd int check, remove stray comedy printf() --- cryptography/hazmat/backends/openssl/urand_engine.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index 67ebe272..0004c50c 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -37,7 +37,7 @@ static const char *Cryptography_urandom_engine_id= "urandom"; static const char *Cryptography_urandom_engine_name = "urandom_engine"; #ifndef _WIN32 -static int urandom_fd; +static int urandom_fd = -1; static int urandom_rand_bytes(unsigned char *buffer, int size) { ssize_t n; @@ -61,10 +61,9 @@ static int urandom_rand_status(void) { static int urandom_init(ENGINE *e) { urandom_fd = open("/dev/urandom", O_RDONLY); - if (urandom_fd > 0) { + if (urandom_fd > -1) { return 1; } else { - printf("crap"); return 0; } } -- cgit v1.2.3 From ad7822c8ab2d5439327594479f2a094d775b90d6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 30 Dec 2013 11:02:25 -0600 Subject: remove unneeded INT_MAX check --- cryptography/hazmat/backends/openssl/urand_engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index 0004c50c..705ff092 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -103,7 +103,7 @@ static int urandom_rand_bytes(unsigned char *buffer, int size) { } while (size > 0) { - chunk = size > INT_MAX ? INT_MAX : size; + chunk = size; if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer)) { return 0; } -- cgit v1.2.3 From 94c3ad66a9e803b7d4d38c750a26b532f2083995 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 30 Dec 2013 11:11:42 -0600 Subject: additional check to verify the ENGINE_new doesn't return null --- cryptography/hazmat/backends/openssl/urand_engine.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index 705ff092..e97476a4 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -133,6 +133,9 @@ static RAND_METHOD urandom_rand = { int Cryptography_add_urandom_engine(void) { ENGINE *e = ENGINE_new(); + if (e == NULL) { + return 0; + } if(!ENGINE_set_id(e, Cryptography_urandom_engine_id) || !ENGINE_set_name(e, Cryptography_urandom_engine_name) || !ENGINE_set_RAND(e, &urandom_rand) || -- cgit v1.2.3 From 3f2524572d6efedb413558c50ba875256eadfaab Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 31 Dec 2013 09:44:32 -0600 Subject: Add dummy engine to tests and test other engine scenarios Modify register_urandom_engine to fix a leak --- cryptography/hazmat/backends/openssl/backend.py | 35 +++--- tests/hazmat/backends/test_openssl.py | 157 +++++++++++++++++++++++- 2 files changed, 172 insertions(+), 20 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index a61e7b05..cfd0cfab 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -193,23 +193,26 @@ class Backend(object): if current_rand != self.ffi.NULL: name = self.lib.ENGINE_get_name(current_rand) assert name != self.ffi.NULL - if name == self.lib.Cryptography_urandom_engine_name: - # urand is already the current default RAND - res = self.lib.ENGINE_finish(current_rand) - assert res == 1 - else: - e = self.lib.ENGINE_by_id(self.lib.Cryptography_urandom_engine_id) - assert e != self.ffi.NULL - res = self.lib.ENGINE_init(e) - assert res == 1 - res = self.lib.ENGINE_set_default_RAND(e) - assert res == 1 - res = self.lib.ENGINE_finish(e) - assert res == 1 - res = self.lib.ENGINE_free(e) + if name != self.lib.Cryptography_urandom_engine_name: + self._register_urandom_engine() + res = self.lib.ENGINE_finish(current_rand) assert res == 1 - # this resets the RNG to use the new engine - self.lib.RAND_cleanup() + else: + self._register_urandom_engine() + + def _register_urandom_engine(self): + e = self.lib.ENGINE_by_id(self.lib.Cryptography_urandom_engine_id) + assert e != self.ffi.NULL + res = self.lib.ENGINE_init(e) + assert res == 1 + res = self.lib.ENGINE_set_default_RAND(e) + assert res == 1 + res = self.lib.ENGINE_finish(e) + assert res == 1 + res = self.lib.ENGINE_free(e) + assert res == 1 + # this resets the RNG to use the new engine + self.lib.RAND_cleanup() def openssl_version_text(self): """ diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 4dd74c35..4be5cd03 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import cffi + import pytest from cryptography import utils @@ -23,6 +25,114 @@ from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC +ffi = cffi.FFI() + +ffi.cdef(""" +static const char *const Cryptography_faux_engine_name; +static const char *const Cryptography_faux_engine_id; +int Cryptography_add_faux_engine(void); +int Cryptography_remove_faux_engine(void); +""") +dummy_engine = ffi.verify( + source=""" + #include + #include + static const char *const Cryptography_faux_engine_name="faux_engine"; + static const char *const Cryptography_faux_engine_id="faux"; + static int faux_bytes(unsigned char *buffer, int size) { + memset(buffer, 1, size); + return 1; + } + static int faux_status(void) { return 1; } + static int faux_init(ENGINE *e) { return 1; } + static int faux_finish(ENGINE *e) { return 1; } + static RAND_METHOD faux_rand = { + NULL, + faux_bytes, + NULL, + NULL, + faux_bytes, + faux_status, + }; + + int Cryptography_add_faux_engine(void) { + ENGINE *e = ENGINE_new(); + if (e == NULL) { + return 0; + } + if(!ENGINE_set_id(e, Cryptography_faux_engine_id) || + !ENGINE_set_name(e, Cryptography_faux_engine_name) || + !ENGINE_set_RAND(e, &faux_rand) || + !ENGINE_set_init_function(e, faux_init) || + !ENGINE_set_finish_function(e, faux_finish)) { + return 0; + } + if (!ENGINE_add(e)) { + ENGINE_free(e); + return 0; + } + if (!ENGINE_free(e)) { + return 0; + } + + return 1; + } + + int Cryptography_remove_faux_engine(void) { + ENGINE *e = ENGINE_by_id(Cryptography_faux_engine_id); + if (e == NULL) { + return 0; + } + if (!ENGINE_remove(e)) { + ENGINE_free(e); + return 0; + } + if (!ENGINE_free(e)) { + return 0; + } + return 1; + } + """, + libraries=["crypto", "ssl"], +) + + +def register_dummy_engine(): + current_rand = backend.lib.ENGINE_get_default_RAND() + assert current_rand != backend.ffi.NULL + name = backend.lib.ENGINE_get_name(current_rand) + assert name != backend.ffi.NULL + assert name != dummy_engine.Cryptography_faux_engine_id + e = backend.lib.ENGINE_by_id(dummy_engine.Cryptography_faux_engine_id) + assert e != backend.ffi.NULL + res = backend.lib.ENGINE_init(e) + assert res == 1 + res = backend.lib.ENGINE_set_default_RAND(e) + assert res == 1 + res = backend.lib.ENGINE_finish(e) + assert res == 1 + res = backend.lib.ENGINE_free(e) + assert res == 1 + # this resets the RNG to use the new engine + backend.lib.RAND_cleanup() + res = backend.lib.ENGINE_finish(current_rand) + assert res == 1 + + +def unregister_dummy_engine(): + e = backend.lib.ENGINE_get_default_RAND() + if e != backend.ffi.NULL: + name = backend.lib.ENGINE_get_name(e) + assert name != backend.ffi.NULL + if name == dummy_engine.Cryptography_faux_engine_name: + backend.lib.ENGINE_unregister_RAND(e) + res = backend.lib.ENGINE_finish(e) + assert res == 1 + backend.lib.RAND_cleanup() + res = backend.lib.ENGINE_free(e) + assert res == 1 + + @utils.register_interface(interfaces.Mode) class DummyMode(object): name = "dummy-mode" @@ -109,11 +219,20 @@ class TestOpenSSL(object): class TestOpenSSLRandomEngine(object): - def setup_method(self, method): + @classmethod + def setup_class(cls): + # add the faux engine to the list of available engines + res = dummy_engine.Cryptography_add_faux_engine() + assert res == 1 + + def teardown_method(self, method): # we need to reset state to being default. backend is a shared global # for all these tests. + unregister_dummy_engine() backend.register_urandom_engine() - pass + current_default = backend.lib.ENGINE_get_default_RAND() + name = backend.lib.ENGINE_get_name(current_default) + assert name == backend.lib.Cryptography_urandom_engine_name def test_register_urandom_already_default(self): e = backend.lib.ENGINE_get_default_RAND() @@ -128,7 +247,7 @@ class TestOpenSSLRandomEngine(object): res = backend.lib.ENGINE_free(e) assert res == 1 - def test_unregister_urandom_engine_already_unregistered(self): + def test_unregister_urandom_engine_nothing_registered(self): backend.unregister_urandom_engine() e = backend.lib.ENGINE_get_default_RAND() assert e == backend.ffi.NULL @@ -141,11 +260,13 @@ class TestOpenSSLRandomEngine(object): assert e != backend.ffi.NULL name = backend.lib.ENGINE_get_name(e) assert name == backend.lib.Cryptography_urandom_engine_name + res = backend.lib.ENGINE_free(e) + assert res == 1 backend.unregister_urandom_engine() e = backend.lib.ENGINE_get_default_RAND() assert e == backend.ffi.NULL - def test_register_urandom_not_default(self): + def test_register_urandom_no_default(self): backend.unregister_urandom_engine() e = backend.lib.ENGINE_get_default_RAND() assert e == backend.ffi.NULL @@ -155,3 +276,31 @@ class TestOpenSSLRandomEngine(object): assert name == backend.lib.Cryptography_urandom_engine_name res = backend.lib.ENGINE_free(e) assert res == 1 + + def test_unregister_urandom_other_engine_default(self): + register_dummy_engine() + default = backend.lib.ENGINE_get_default_RAND() + default_name = backend.lib.ENGINE_get_name(default) + assert default_name == dummy_engine.Cryptography_faux_engine_name + res = backend.lib.ENGINE_finish(default) + assert res == 1 + backend.unregister_urandom_engine() + current_default = backend.lib.ENGINE_get_default_RAND() + name = backend.lib.ENGINE_get_name(current_default) + assert name == dummy_engine.Cryptography_faux_engine_name + res = backend.lib.ENGINE_finish(current_default) + assert res == 1 + + def test_register_urandom_other_engine_default(self): + register_dummy_engine() + default = backend.lib.ENGINE_get_default_RAND() + default_name = backend.lib.ENGINE_get_name(default) + assert default_name == dummy_engine.Cryptography_faux_engine_name + res = backend.lib.ENGINE_finish(default) + assert res == 1 + backend.register_urandom_engine() + current_default = backend.lib.ENGINE_get_default_RAND() + name = backend.lib.ENGINE_get_name(current_default) + assert name == backend.lib.Cryptography_urandom_engine_name + res = backend.lib.ENGINE_finish(current_default) + assert res == 1 -- cgit v1.2.3 From 53473d3447fd6ad5d70810da3e638e6e7a59afbb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 31 Dec 2013 12:00:37 -0600 Subject: improve init/finish engine funcs, do a better job inc/dec struct/func refs --- cryptography/hazmat/backends/openssl/backend.py | 10 +++++---- .../hazmat/backends/openssl/urand_engine.py | 14 ++++++++++++- tests/hazmat/backends/test_openssl.py | 24 +++------------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index cfd0cfab..93d15740 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -183,10 +183,10 @@ class Backend(object): assert name != self.ffi.NULL if name == self.lib.Cryptography_urandom_engine_name: self.lib.ENGINE_unregister_RAND(e) - res = self.lib.ENGINE_free(e) - assert res == 1 # this resets the RNG to use the new engine self.lib.RAND_cleanup() + res = self.lib.ENGINE_finish(e) + assert res == 1 def register_urandom_engine(self): current_rand = self.lib.ENGINE_get_default_RAND() @@ -207,10 +207,12 @@ class Backend(object): assert res == 1 res = self.lib.ENGINE_set_default_RAND(e) assert res == 1 - res = self.lib.ENGINE_finish(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 # this resets the RNG to use the new engine self.lib.RAND_cleanup() diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index e97476a4..673b1480 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -60,6 +60,9 @@ static int urandom_rand_status(void) { } static int urandom_init(ENGINE *e) { + if (urandom_fd > -1) { + return 1; + } urandom_fd = open("/dev/urandom", O_RDONLY); if (urandom_fd > -1) { return 1; @@ -76,6 +79,7 @@ static int urandom_finish(ENGINE *e) { if (n < 0) { return 0; } else { + urandom_fd = -1; return 1; } } @@ -87,6 +91,9 @@ static int urandom_finish(ENGINE *e) { static HCRYPTPROV hCryptProv = 0; static int urandom_init(ENGINE *e) { + if (hCryptProv > 0) { + return 1; + } if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { return 1; @@ -114,7 +121,12 @@ static int urandom_rand_bytes(unsigned char *buffer, int size) { } static int urandom_finish(ENGINE *e) { - return 1; + if (CryptReleaseContext(hCryptProv, 0)) { + hCryptProv = 0; + return 1; + } else { + return 0; + } } static int urandom_rand_status(void) { diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 4be5cd03..82832b10 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -31,7 +31,6 @@ ffi.cdef(""" static const char *const Cryptography_faux_engine_name; static const char *const Cryptography_faux_engine_id; int Cryptography_add_faux_engine(void); -int Cryptography_remove_faux_engine(void); """) dummy_engine = ffi.verify( source=""" @@ -77,21 +76,6 @@ dummy_engine = ffi.verify( return 1; } - - int Cryptography_remove_faux_engine(void) { - ENGINE *e = ENGINE_by_id(Cryptography_faux_engine_id); - if (e == NULL) { - return 0; - } - if (!ENGINE_remove(e)) { - ENGINE_free(e); - return 0; - } - if (!ENGINE_free(e)) { - return 0; - } - return 1; - } """, libraries=["crypto", "ssl"], ) @@ -103,6 +87,8 @@ def register_dummy_engine(): name = backend.lib.ENGINE_get_name(current_rand) assert name != backend.ffi.NULL assert name != dummy_engine.Cryptography_faux_engine_id + res = backend.lib.ENGINE_finish(current_rand) + assert res == 1 e = backend.lib.ENGINE_by_id(dummy_engine.Cryptography_faux_engine_id) assert e != backend.ffi.NULL res = backend.lib.ENGINE_init(e) @@ -115,8 +101,6 @@ def register_dummy_engine(): assert res == 1 # this resets the RNG to use the new engine backend.lib.RAND_cleanup() - res = backend.lib.ENGINE_finish(current_rand) - assert res == 1 def unregister_dummy_engine(): @@ -126,10 +110,8 @@ def unregister_dummy_engine(): assert name != backend.ffi.NULL if name == dummy_engine.Cryptography_faux_engine_name: backend.lib.ENGINE_unregister_RAND(e) - res = backend.lib.ENGINE_finish(e) - assert res == 1 backend.lib.RAND_cleanup() - res = backend.lib.ENGINE_free(e) + res = backend.lib.ENGINE_finish(e) assert res == 1 -- cgit v1.2.3 From efdcbd909a47c6d6660bf621f2a8c488fde06f88 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 31 Dec 2013 12:07:42 -0600 Subject: check if the fd is available via engine status --- cryptography/hazmat/backends/openssl/urand_engine.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index 673b1480..6cbdab41 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -56,7 +56,11 @@ static int urandom_rand_bytes(unsigned char *buffer, int size) { } static int urandom_rand_status(void) { - return 1; + if (urandom_fd == -1) { + return 0; + } else { + return 1; + } } static int urandom_init(ENGINE *e) { @@ -130,7 +134,11 @@ static int urandom_finish(ENGINE *e) { } static int urandom_rand_status(void) { - return 1; + if (hCryptProv == 0) { + return 0; + } else { + return 1; + } } #endif /* MS_WINDOWS */ -- cgit v1.2.3 From 6dc48243725eccfcb59c622e4b8ef1e74f3b3f67 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 31 Dec 2013 12:09:28 -0600 Subject: remove inaccurate comment --- cryptography/hazmat/backends/openssl/urand_engine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py index 6cbdab41..ff5e5613 100644 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ b/cryptography/hazmat/backends/openssl/urand_engine.py @@ -90,8 +90,6 @@ static int urandom_finish(ENGINE *e) { #endif #ifdef _WIN32 -/* This handle is never explicitly released. Instead, the operating - system will release it when the process terminates. */ static HCRYPTPROV hCryptProv = 0; static int urandom_init(ENGINE *e) { -- cgit v1.2.3 From 77389ac83db5a04e173fce52170dd8d2003e5560 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 31 Dec 2013 13:32:50 -0600 Subject: rename urandom engine to osrandom engine --- cryptography/hazmat/backends/openssl/backend.py | 24 +-- .../hazmat/backends/openssl/osrand_engine.py | 176 +++++++++++++++++++++ .../hazmat/backends/openssl/urand_engine.py | 176 --------------------- tests/hazmat/backends/test_openssl.py | 46 +++--- 4 files changed, 211 insertions(+), 211 deletions(-) create mode 100644 cryptography/hazmat/backends/openssl/osrand_engine.py delete mode 100644 cryptography/hazmat/backends/openssl/urand_engine.py diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 93d15740..5a28b2d4 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -93,7 +93,7 @@ class Backend(object): "rand", "rsa", "ssl", - "urand_engine", + "osrand_engine", "x509", "x509name", "x509v3", @@ -107,7 +107,7 @@ class Backend(object): self._cipher_registry = {} self._register_default_ciphers() - self.register_urandom_engine() + self.register_osrandom_engine() @classmethod def _ensure_ffi_initialized(cls): @@ -172,36 +172,36 @@ class Backend(object): cls.lib.OpenSSL_add_all_algorithms() cls.lib.SSL_load_error_strings() - # Add the urandom engine to the engine list - res = cls.lib.Cryptography_add_urandom_engine() + # Add the osrandom engine to the engine list + res = cls.lib.Cryptography_add_osrandom_engine() assert res == 1 - def unregister_urandom_engine(self): + def unregister_osrandom_engine(self): e = self.lib.ENGINE_get_default_RAND() if e != self.ffi.NULL: name = self.lib.ENGINE_get_name(e) assert name != self.ffi.NULL - if name == self.lib.Cryptography_urandom_engine_name: + if name == self.lib.Cryptography_osrandom_engine_name: self.lib.ENGINE_unregister_RAND(e) # this resets the RNG to use the new engine self.lib.RAND_cleanup() res = self.lib.ENGINE_finish(e) assert res == 1 - def register_urandom_engine(self): + def register_osrandom_engine(self): current_rand = self.lib.ENGINE_get_default_RAND() if current_rand != self.ffi.NULL: name = self.lib.ENGINE_get_name(current_rand) assert name != self.ffi.NULL - if name != self.lib.Cryptography_urandom_engine_name: - self._register_urandom_engine() + if name != self.lib.Cryptography_osrandom_engine_name: + self._register_osrandom_engine() res = self.lib.ENGINE_finish(current_rand) assert res == 1 else: - self._register_urandom_engine() + self._register_osrandom_engine() - def _register_urandom_engine(self): - e = self.lib.ENGINE_by_id(self.lib.Cryptography_urandom_engine_id) + def _register_osrandom_engine(self): + e = self.lib.ENGINE_by_id(self.lib.Cryptography_osrandom_engine_id) assert e != self.ffi.NULL res = self.lib.ENGINE_init(e) assert res == 1 diff --git a/cryptography/hazmat/backends/openssl/osrand_engine.py b/cryptography/hazmat/backends/openssl/osrand_engine.py new file mode 100644 index 00000000..b0cdf80f --- /dev/null +++ b/cryptography/hazmat/backends/openssl/osrand_engine.py @@ -0,0 +1,176 @@ +# 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 +#else +#include +#include +#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 = """ +""" + +CUSTOMIZATIONS = """ +static const char *Cryptography_osrandom_engine_id= "osrandom"; +static const char *Cryptography_osrandom_engine_name = "osrandom_engine"; + +#ifndef _WIN32 +static int urandom_fd = -1; + +static int osrandom_rand_bytes(unsigned char *buffer, int size) { + ssize_t n; + while (0 < size) { + do { + n = read(urandom_fd, buffer, (size_t)size); + } while (n < 0 && errno == EINTR); + if (n <= 0) { + return 0; + break; + } + buffer += n; + size -= n; + } + return 1; +} + +static int osrandom_rand_status(void) { + if (urandom_fd == -1) { + return 0; + } else { + return 1; + } +} + +static int osrandom_init(ENGINE *e) { + if (urandom_fd > -1) { + return 1; + } + urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd > -1) { + return 1; + } else { + return 0; + } +} + +static int osrandom_finish(ENGINE *e) { + int n; + do { + n = close(urandom_fd); + } while (n < 0 && errno == EINTR); + if (n < 0) { + return 0; + } else { + urandom_fd = -1; + return 1; + } +} +#endif + +#ifdef _WIN32 +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) { + size_t chunk; + + if (hCryptProv == 0) { + return 0; + } + + while (size > 0) { + chunk = size; + if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer)) { + return 0; + } + buffer += chunk; + size -= chunk; + } + 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; + } +} +#endif /* MS_WINDOWS */ + +static RAND_METHOD osrandom_rand = { + NULL, + osrandom_rand_bytes, + NULL, + NULL, + osrandom_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)) { + return 0; + } + if (!ENGINE_add(e)) { + ENGINE_free(e); + return 0; + } + if (!ENGINE_free(e)) { + return 0; + } + + return 1; +} +""" + +CONDITIONAL_NAMES = {} diff --git a/cryptography/hazmat/backends/openssl/urand_engine.py b/cryptography/hazmat/backends/openssl/urand_engine.py deleted file mode 100644 index ff5e5613..00000000 --- a/cryptography/hazmat/backends/openssl/urand_engine.py +++ /dev/null @@ -1,176 +0,0 @@ -# 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 -#else -#include -#include -#endif -""" - -TYPES = """ -static const char *const Cryptography_urandom_engine_name; -static const char *const Cryptography_urandom_engine_id; -""" - -FUNCTIONS = """ -int Cryptography_add_urandom_engine(void); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -static const char *Cryptography_urandom_engine_id= "urandom"; -static const char *Cryptography_urandom_engine_name = "urandom_engine"; - -#ifndef _WIN32 -static int urandom_fd = -1; - -static int urandom_rand_bytes(unsigned char *buffer, int size) { - ssize_t n; - while (0 < size) { - do { - n = read(urandom_fd, buffer, (size_t)size); - } while (n < 0 && errno == EINTR); - if (n <= 0) { - return 0; - break; - } - buffer += n; - size -= n; - } - return 1; -} - -static int urandom_rand_status(void) { - if (urandom_fd == -1) { - return 0; - } else { - return 1; - } -} - -static int urandom_init(ENGINE *e) { - if (urandom_fd > -1) { - return 1; - } - urandom_fd = open("/dev/urandom", O_RDONLY); - if (urandom_fd > -1) { - return 1; - } else { - return 0; - } -} - -static int urandom_finish(ENGINE *e) { - int n; - do { - n = close(urandom_fd); - } while (n < 0 && errno == EINTR); - if (n < 0) { - return 0; - } else { - urandom_fd = -1; - return 1; - } -} -#endif - -#ifdef _WIN32 -static HCRYPTPROV hCryptProv = 0; - -static int urandom_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 urandom_rand_bytes(unsigned char *buffer, int size) { - size_t chunk; - - if (hCryptProv == 0) { - return 0; - } - - while (size > 0) { - chunk = size; - if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer)) { - return 0; - } - buffer += chunk; - size -= chunk; - } - return 1; -} - -static int urandom_finish(ENGINE *e) { - if (CryptReleaseContext(hCryptProv, 0)) { - hCryptProv = 0; - return 1; - } else { - return 0; - } -} - -static int urandom_rand_status(void) { - if (hCryptProv == 0) { - return 0; - } else { - return 1; - } -} -#endif /* MS_WINDOWS */ - -static RAND_METHOD urandom_rand = { - NULL, - urandom_rand_bytes, - NULL, - NULL, - urandom_rand_bytes, - urandom_rand_status, -}; - -int Cryptography_add_urandom_engine(void) { - ENGINE *e = ENGINE_new(); - if (e == NULL) { - return 0; - } - if(!ENGINE_set_id(e, Cryptography_urandom_engine_id) || - !ENGINE_set_name(e, Cryptography_urandom_engine_name) || - !ENGINE_set_RAND(e, &urandom_rand) || - !ENGINE_set_init_function(e, urandom_init) || - !ENGINE_set_finish_function(e, urandom_finish)) { - return 0; - } - if (!ENGINE_add(e)) { - ENGINE_free(e); - return 0; - } - if (!ENGINE_free(e)) { - return 0; - } - - return 1; -} -""" - -CONDITIONAL_NAMES = {} diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 82832b10..3fabfe38 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -192,10 +192,10 @@ class TestOpenSSL(object): # This test is not in the next class because to check if it's really # default we don't want to run the setup_method before it - def test_urandom_engine_is_default(self): + def test_osrandom_engine_is_default(self): e = backend.lib.ENGINE_get_default_RAND() name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_urandom_engine_name + assert name == backend.lib.Cryptography_osrandom_engine_name res = backend.lib.ENGINE_free(e) assert res == 1 @@ -211,78 +211,78 @@ class TestOpenSSLRandomEngine(object): # we need to reset state to being default. backend is a shared global # for all these tests. unregister_dummy_engine() - backend.register_urandom_engine() + backend.register_osrandom_engine() current_default = backend.lib.ENGINE_get_default_RAND() name = backend.lib.ENGINE_get_name(current_default) - assert name == backend.lib.Cryptography_urandom_engine_name + assert name == backend.lib.Cryptography_osrandom_engine_name - def test_register_urandom_already_default(self): + def test_register_osrandom_already_default(self): e = backend.lib.ENGINE_get_default_RAND() name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_urandom_engine_name + assert name == backend.lib.Cryptography_osrandom_engine_name res = backend.lib.ENGINE_free(e) assert res == 1 - backend.register_urandom_engine() + backend.register_osrandom_engine() e = backend.lib.ENGINE_get_default_RAND() name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_urandom_engine_name + assert name == backend.lib.Cryptography_osrandom_engine_name res = backend.lib.ENGINE_free(e) assert res == 1 - def test_unregister_urandom_engine_nothing_registered(self): - backend.unregister_urandom_engine() + def test_unregister_osrandom_engine_nothing_registered(self): + backend.unregister_osrandom_engine() e = backend.lib.ENGINE_get_default_RAND() assert e == backend.ffi.NULL - backend.unregister_urandom_engine() + backend.unregister_osrandom_engine() e = backend.lib.ENGINE_get_default_RAND() assert e == backend.ffi.NULL - def test_unregister_urandom_engine(self): + def test_unregister_osrandom_engine(self): e = backend.lib.ENGINE_get_default_RAND() assert e != backend.ffi.NULL name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_urandom_engine_name + assert name == backend.lib.Cryptography_osrandom_engine_name res = backend.lib.ENGINE_free(e) assert res == 1 - backend.unregister_urandom_engine() + backend.unregister_osrandom_engine() e = backend.lib.ENGINE_get_default_RAND() assert e == backend.ffi.NULL - def test_register_urandom_no_default(self): - backend.unregister_urandom_engine() + def test_register_osrandom_no_default(self): + backend.unregister_osrandom_engine() e = backend.lib.ENGINE_get_default_RAND() assert e == backend.ffi.NULL - backend.register_urandom_engine() + backend.register_osrandom_engine() e = backend.lib.ENGINE_get_default_RAND() name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_urandom_engine_name + assert name == backend.lib.Cryptography_osrandom_engine_name res = backend.lib.ENGINE_free(e) assert res == 1 - def test_unregister_urandom_other_engine_default(self): + def test_unregister_osrandom_other_engine_default(self): register_dummy_engine() default = backend.lib.ENGINE_get_default_RAND() default_name = backend.lib.ENGINE_get_name(default) assert default_name == dummy_engine.Cryptography_faux_engine_name res = backend.lib.ENGINE_finish(default) assert res == 1 - backend.unregister_urandom_engine() + backend.unregister_osrandom_engine() current_default = backend.lib.ENGINE_get_default_RAND() name = backend.lib.ENGINE_get_name(current_default) assert name == dummy_engine.Cryptography_faux_engine_name res = backend.lib.ENGINE_finish(current_default) assert res == 1 - def test_register_urandom_other_engine_default(self): + def test_register_osrandom_other_engine_default(self): register_dummy_engine() default = backend.lib.ENGINE_get_default_RAND() default_name = backend.lib.ENGINE_get_name(default) assert default_name == dummy_engine.Cryptography_faux_engine_name res = backend.lib.ENGINE_finish(default) assert res == 1 - backend.register_urandom_engine() + backend.register_osrandom_engine() current_default = backend.lib.ENGINE_get_default_RAND() name = backend.lib.ENGINE_get_name(current_default) - assert name == backend.lib.Cryptography_urandom_engine_name + assert name == backend.lib.Cryptography_osrandom_engine_name res = backend.lib.ENGINE_finish(current_default) assert res == 1 -- cgit v1.2.3 From 607688cdcb5b262715bd4eb70f9770f0326ce9e5 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 1 Jan 2014 10:34:14 -0600 Subject: remove stray break, add FD_CLOEXEC, reset fd var even if close fails --- cryptography/hazmat/backends/openssl/osrand_engine.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/backends/openssl/osrand_engine.py b/cryptography/hazmat/backends/openssl/osrand_engine.py index b0cdf80f..bca2d79d 100644 --- a/cryptography/hazmat/backends/openssl/osrand_engine.py +++ b/cryptography/hazmat/backends/openssl/osrand_engine.py @@ -47,7 +47,6 @@ static int osrandom_rand_bytes(unsigned char *buffer, int size) { } while (n < 0 && errno == EINTR); if (n <= 0) { return 0; - break; } buffer += n; size -= n; @@ -69,6 +68,9 @@ static int osrandom_init(ENGINE *e) { } urandom_fd = open("/dev/urandom", O_RDONLY); if (urandom_fd > -1) { + if (fcntl(urandom_fd, F_SETFD, FD_CLOEXEC) == -1) { + return 0; + } return 1; } else { return 0; @@ -81,6 +83,7 @@ static int osrandom_finish(ENGINE *e) { n = close(urandom_fd); } while (n < 0 && errno == EINTR); if (n < 0) { + urandom_fd = -1; return 0; } else { urandom_fd = -1; -- cgit v1.2.3 From 9ad4d755bb3a2edfb8e46b60f6dfaff6365f0386 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 2 Jan 2014 15:20:50 -0600 Subject: handle lib/ffi on backend becoming private --- cryptography/hazmat/backends/openssl/backend.py | 42 ++++---- tests/hazmat/backends/test_openssl.py | 128 ++++++++++++------------ 2 files changed, 85 insertions(+), 85 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 0e6e3acf..089684ad 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -51,44 +51,44 @@ class Backend(object): self.register_osrandom_engine() def unregister_osrandom_engine(self): - e = self.lib.ENGINE_get_default_RAND() - if e != self.ffi.NULL: - name = self.lib.ENGINE_get_name(e) - assert name != self.ffi.NULL - if name == self.lib.Cryptography_osrandom_engine_name: - self.lib.ENGINE_unregister_RAND(e) + e = self._lib.ENGINE_get_default_RAND() + if e != self._ffi.NULL: + name = self._lib.ENGINE_get_name(e) + assert name != self._ffi.NULL + if name == self._lib.Cryptography_osrandom_engine_name: + self._lib.ENGINE_unregister_RAND(e) # this resets the RNG to use the new engine - self.lib.RAND_cleanup() - res = self.lib.ENGINE_finish(e) + self._lib.RAND_cleanup() + res = self._lib.ENGINE_finish(e) assert res == 1 def register_osrandom_engine(self): - current_rand = self.lib.ENGINE_get_default_RAND() - if current_rand != self.ffi.NULL: - name = self.lib.ENGINE_get_name(current_rand) - assert name != self.ffi.NULL - if name != self.lib.Cryptography_osrandom_engine_name: + current_rand = self._lib.ENGINE_get_default_RAND() + if current_rand != self._ffi.NULL: + name = self._lib.ENGINE_get_name(current_rand) + assert name != self._ffi.NULL + if name != self._lib.Cryptography_osrandom_engine_name: self._register_osrandom_engine() - res = self.lib.ENGINE_finish(current_rand) + res = self._lib.ENGINE_finish(current_rand) assert res == 1 else: self._register_osrandom_engine() def _register_osrandom_engine(self): - e = self.lib.ENGINE_by_id(self.lib.Cryptography_osrandom_engine_id) - assert e != self.ffi.NULL - res = self.lib.ENGINE_init(e) + e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) + assert e != self._ffi.NULL + res = self._lib.ENGINE_init(e) assert res == 1 - res = self.lib.ENGINE_set_default_RAND(e) + 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) + res = self._lib.ENGINE_free(e) assert res == 1 # decrement the functional ref incremented by ENGINE_init - res = self.lib.ENGINE_finish(e) + res = self._lib.ENGINE_finish(e) assert res == 1 # this resets the RNG to use the new engine - self.lib.RAND_cleanup() + self._lib.RAND_cleanup() def openssl_version_text(self): """ diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 6fc1e583..b7d999b8 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -82,36 +82,36 @@ dummy_engine = ffi.verify( def register_dummy_engine(): - current_rand = backend.lib.ENGINE_get_default_RAND() - assert current_rand != backend.ffi.NULL - name = backend.lib.ENGINE_get_name(current_rand) - assert name != backend.ffi.NULL + current_rand = backend._lib.ENGINE_get_default_RAND() + assert current_rand != backend._ffi.NULL + name = backend._lib.ENGINE_get_name(current_rand) + assert name != backend._ffi.NULL assert name != dummy_engine.Cryptography_faux_engine_id - res = backend.lib.ENGINE_finish(current_rand) + res = backend._lib.ENGINE_finish(current_rand) assert res == 1 - e = backend.lib.ENGINE_by_id(dummy_engine.Cryptography_faux_engine_id) - assert e != backend.ffi.NULL - res = backend.lib.ENGINE_init(e) + e = backend._lib.ENGINE_by_id(dummy_engine.Cryptography_faux_engine_id) + assert e != backend._ffi.NULL + res = backend._lib.ENGINE_init(e) assert res == 1 - res = backend.lib.ENGINE_set_default_RAND(e) + res = backend._lib.ENGINE_set_default_RAND(e) assert res == 1 - res = backend.lib.ENGINE_finish(e) + res = backend._lib.ENGINE_finish(e) assert res == 1 - res = backend.lib.ENGINE_free(e) + res = backend._lib.ENGINE_free(e) assert res == 1 # this resets the RNG to use the new engine - backend.lib.RAND_cleanup() + backend._lib.RAND_cleanup() def unregister_dummy_engine(): - e = backend.lib.ENGINE_get_default_RAND() - if e != backend.ffi.NULL: - name = backend.lib.ENGINE_get_name(e) - assert name != backend.ffi.NULL + e = backend._lib.ENGINE_get_default_RAND() + if e != backend._ffi.NULL: + name = backend._lib.ENGINE_get_name(e) + assert name != backend._ffi.NULL if name == dummy_engine.Cryptography_faux_engine_name: - backend.lib.ENGINE_unregister_RAND(e) - backend.lib.RAND_cleanup() - res = backend.lib.ENGINE_finish(e) + backend._lib.ENGINE_unregister_RAND(e) + backend._lib.RAND_cleanup() + res = backend._lib.ENGINE_finish(e) assert res == 1 @@ -188,10 +188,10 @@ class TestOpenSSL(object): # This test is not in the next class because to check if it's really # default we don't want to run the setup_method before it def test_osrandom_engine_is_default(self): - e = backend.lib.ENGINE_get_default_RAND() - name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_osrandom_engine_name - res = backend.lib.ENGINE_free(e) + e = backend._lib.ENGINE_get_default_RAND() + name = backend._lib.ENGINE_get_name(e) + assert name == backend._lib.Cryptography_osrandom_engine_name + res = backend._lib.ENGINE_free(e) assert res == 1 @@ -207,77 +207,77 @@ class TestOpenSSLRandomEngine(object): # for all these tests. unregister_dummy_engine() backend.register_osrandom_engine() - current_default = backend.lib.ENGINE_get_default_RAND() - name = backend.lib.ENGINE_get_name(current_default) - assert name == backend.lib.Cryptography_osrandom_engine_name + current_default = backend._lib.ENGINE_get_default_RAND() + name = backend._lib.ENGINE_get_name(current_default) + assert name == backend._lib.Cryptography_osrandom_engine_name def test_register_osrandom_already_default(self): - e = backend.lib.ENGINE_get_default_RAND() - name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_osrandom_engine_name - res = backend.lib.ENGINE_free(e) + e = backend._lib.ENGINE_get_default_RAND() + name = backend._lib.ENGINE_get_name(e) + assert name == backend._lib.Cryptography_osrandom_engine_name + res = backend._lib.ENGINE_free(e) assert res == 1 backend.register_osrandom_engine() - e = backend.lib.ENGINE_get_default_RAND() - name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_osrandom_engine_name - res = backend.lib.ENGINE_free(e) + e = backend._lib.ENGINE_get_default_RAND() + name = backend._lib.ENGINE_get_name(e) + assert name == backend._lib.Cryptography_osrandom_engine_name + res = backend._lib.ENGINE_free(e) assert res == 1 def test_unregister_osrandom_engine_nothing_registered(self): backend.unregister_osrandom_engine() - e = backend.lib.ENGINE_get_default_RAND() - assert e == backend.ffi.NULL + e = backend._lib.ENGINE_get_default_RAND() + assert e == backend._ffi.NULL backend.unregister_osrandom_engine() - e = backend.lib.ENGINE_get_default_RAND() - assert e == backend.ffi.NULL + e = backend._lib.ENGINE_get_default_RAND() + assert e == backend._ffi.NULL def test_unregister_osrandom_engine(self): - e = backend.lib.ENGINE_get_default_RAND() - assert e != backend.ffi.NULL - name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_osrandom_engine_name - res = backend.lib.ENGINE_free(e) + e = backend._lib.ENGINE_get_default_RAND() + assert e != backend._ffi.NULL + name = backend._lib.ENGINE_get_name(e) + assert name == backend._lib.Cryptography_osrandom_engine_name + res = backend._lib.ENGINE_free(e) assert res == 1 backend.unregister_osrandom_engine() - e = backend.lib.ENGINE_get_default_RAND() - assert e == backend.ffi.NULL + e = backend._lib.ENGINE_get_default_RAND() + assert e == backend._ffi.NULL def test_register_osrandom_no_default(self): backend.unregister_osrandom_engine() - e = backend.lib.ENGINE_get_default_RAND() - assert e == backend.ffi.NULL + e = backend._lib.ENGINE_get_default_RAND() + assert e == backend._ffi.NULL backend.register_osrandom_engine() - e = backend.lib.ENGINE_get_default_RAND() - name = backend.lib.ENGINE_get_name(e) - assert name == backend.lib.Cryptography_osrandom_engine_name - res = backend.lib.ENGINE_free(e) + e = backend._lib.ENGINE_get_default_RAND() + name = backend._lib.ENGINE_get_name(e) + assert name == backend._lib.Cryptography_osrandom_engine_name + res = backend._lib.ENGINE_free(e) assert res == 1 def test_unregister_osrandom_other_engine_default(self): register_dummy_engine() - default = backend.lib.ENGINE_get_default_RAND() - default_name = backend.lib.ENGINE_get_name(default) + default = backend._lib.ENGINE_get_default_RAND() + default_name = backend._lib.ENGINE_get_name(default) assert default_name == dummy_engine.Cryptography_faux_engine_name - res = backend.lib.ENGINE_finish(default) + res = backend._lib.ENGINE_finish(default) assert res == 1 backend.unregister_osrandom_engine() - current_default = backend.lib.ENGINE_get_default_RAND() - name = backend.lib.ENGINE_get_name(current_default) + current_default = backend._lib.ENGINE_get_default_RAND() + name = backend._lib.ENGINE_get_name(current_default) assert name == dummy_engine.Cryptography_faux_engine_name - res = backend.lib.ENGINE_finish(current_default) + res = backend._lib.ENGINE_finish(current_default) assert res == 1 def test_register_osrandom_other_engine_default(self): register_dummy_engine() - default = backend.lib.ENGINE_get_default_RAND() - default_name = backend.lib.ENGINE_get_name(default) + default = backend._lib.ENGINE_get_default_RAND() + default_name = backend._lib.ENGINE_get_name(default) assert default_name == dummy_engine.Cryptography_faux_engine_name - res = backend.lib.ENGINE_finish(default) + res = backend._lib.ENGINE_finish(default) assert res == 1 backend.register_osrandom_engine() - current_default = backend.lib.ENGINE_get_default_RAND() - name = backend.lib.ENGINE_get_name(current_default) - assert name == backend.lib.Cryptography_osrandom_engine_name - res = backend.lib.ENGINE_finish(current_default) + current_default = backend._lib.ENGINE_get_default_RAND() + name = backend._lib.ENGINE_get_name(current_default) + assert name == backend._lib.Cryptography_osrandom_engine_name + res = backend._lib.ENGINE_finish(current_default) assert res == 1 -- cgit v1.2.3 From 3f17c7c68157ec04b98cb5fd61216a6644aa3a7c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 20 Jan 2014 16:32:26 -0600 Subject: first pass at adding docs for the engine. lvh has graciously agreed to draft some language to explain the rationale behind choosing the system random over userspace rand --- docs/hazmat/backends/openssl.rst | 29 ++++++++++++++++++++++++++++- docs/spelling_wordlist.txt | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index a1f2d28a..469823f1 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -7,12 +7,39 @@ The `OpenSSL`_ C library. .. data:: cryptography.hazmat.backends.openssl.backend - This is the exposed API for the OpenSSL backend. It has one public attribute. + This is the exposed API for the OpenSSL backend. .. attribute:: name The string name of this backend: ``"openssl"`` + .. method:: register_osrandom_engine() + + Registers the OS random engine as default. This will effectively + disable OpenSSL's default CSPRNG. + + .. method:: unregister_osrandom_engine() + + Unregisters the OS random engine if it is default. This will restore + the default OpenSSL CSPRNG. If the OS random engine is not the default + engine (e.g. if another engine is set as default) nothing will be + changed. + +OS Random Engine +---------------- + +OpenSSL has a CSPRNG that it seeds when starting up. Unfortunately, its state +is replicated when the process is forked and child processes can deliver +similar or identical random values. OpenSSL has landed a patch to mitigate this +issue, but this project can't rely on users having recent versions. + +To work around this cryptography uses a custom OpenSSL engine that replaces the +standard random source with one that fetches entropy from ``/dev/urandom`` (or +CryptGenRandom on Windows). This engine is **active** by default when importing +the OpenSSL backend. It is added to the engine list but not activated if you +only import the binding. + + Using your own OpenSSL on Linux ------------------------------- diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 75628ba5..e05efc6c 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -27,3 +27,4 @@ Changelog Docstrings Fernet Schneier +Unregisters -- cgit v1.2.3 From 136ff17aceac8b61cd1c3f12774c3d1f9cf6742a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Jan 2014 21:23:11 -0600 Subject: update random engine docs --- docs/hazmat/backends/openssl.rst | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 5ad00d03..17d01ca8 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -28,15 +28,25 @@ The `OpenSSL`_ C library. OS Random Engine ---------------- -OpenSSL has a CSPRNG that it seeds when starting up. Unfortunately, its state -is replicated when the process is forked and child processes can deliver -similar or identical random values. OpenSSL has landed a patch to mitigate this -issue, but this project can't rely on users having recent versions. - -To work around this cryptography uses a custom OpenSSL engine that replaces the -standard random source with one that fetches entropy from ``/dev/urandom`` (or -CryptGenRandom on Windows). This engine is **active** by default when importing -the OpenSSL backend. It is added to the engine list but not activated if you -only import the binding. +OpenSSL uses a userspace CSPRNG that is seeded from system random ( +``/dev/urandom`` or ``CryptGenRandom``). This CSPRNG is not reseeded +automatically when a process calls ``fork()``. This can result in situations +where two different processes can return similar or identical keys and +compromise the security of the system. + +The approach this project has chosen to mitigate this vulnerability is to +include an engine that replaces the OpenSSL default CSPRNG with one that sources +its entropy from ``/dev/urandom`` on UNIX-like operating systems and uses +``CryptGenRandom`` on Windows. This method of pulling from the system pool +allows us to avoid potential issues with `initializing the RNG`_ as well as +protecting us from the ``fork()`` weakness. + +This engine is **active** by default when importing the OpenSSL backend. It is +added to the engine list but **not activated** if you only import the binding. +If you wish to deactivate it call ``unregister_osrandom_engine()`` on the +backend object. .. _`OpenSSL`: https://www.openssl.org/ +.. _`initializing the RNG`: http://en.wikipedia.org/wiki/OpenSSL#Vulnerability_in_the_Debian_implementation +.. _`Yarrow`: http://en.wikipedia.org/wiki/Yarrow_algorithm +.. _`Fortuna`: http://en.wikipedia.org/wiki/Fortuna_(PRNG) -- cgit v1.2.3 From 9967bc5c378ea2e72cc6c034e22bca6588ca2f29 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Jan 2014 21:39:13 -0600 Subject: add a little info about the various system randoms. maybe useful? --- docs/hazmat/backends/openssl.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 17d01ca8..16519d18 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -46,6 +46,18 @@ added to the engine list but **not activated** if you only import the binding. If you wish to deactivate it call ``unregister_osrandom_engine()`` on the backend object. +OS Random Sources +---------------------------- + +On OS X and FreeBSD ``/dev/urandom`` is an alias for ``/dev/random`` and +utilizes the `Yarrow`_ algorithm. + +On Windows ``CryptGenRandom`` is backed by `Fortuna`_. + +Linux uses its own PRNG design. ``/dev/urandom`` is a non-blocking source seeded +from the ``/dev/random`` pool. + + .. _`OpenSSL`: https://www.openssl.org/ .. _`initializing the RNG`: http://en.wikipedia.org/wiki/OpenSSL#Vulnerability_in_the_Debian_implementation .. _`Yarrow`: http://en.wikipedia.org/wiki/Yarrow_algorithm -- cgit v1.2.3 From 55809a16fd82f414774252f9788593776ad26687 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Jan 2014 21:41:16 -0600 Subject: rst syntax --- docs/hazmat/backends/openssl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 16519d18..b7133deb 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -47,7 +47,7 @@ If you wish to deactivate it call ``unregister_osrandom_engine()`` on the backend object. OS Random Sources ----------------------------- +----------------- On OS X and FreeBSD ``/dev/urandom`` is an alias for ``/dev/random`` and utilizes the `Yarrow`_ algorithm. -- cgit v1.2.3 From ec0f7393695c7cfd715f867906598ab77bda19bb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Jan 2014 21:52:24 -0600 Subject: link against advapi32 on windows --- cryptography/hazmat/bindings/openssl/binding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py index 9df26cde..843bd3ea 100644 --- a/cryptography/hazmat/bindings/openssl/binding.py +++ b/cryptography/hazmat/bindings/openssl/binding.py @@ -91,7 +91,7 @@ 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, -- cgit v1.2.3 From a85baf166b9d9aec6e662a0657d2d21bcfd3df28 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Jan 2014 22:15:51 -0600 Subject: add windows support to random engine tests --- tests/hazmat/backends/test_openssl.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index e527ed19..ea716204 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys + import cffi import pytest @@ -25,6 +27,11 @@ from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC +if sys.platform != "win32": + libraries = ["crypto", "ssl"] +else: # pragma: no cover + libraries = ["libeay32", "ssleay32", "advapi32"] + ffi = cffi.FFI() ffi.cdef(""" @@ -77,7 +84,7 @@ dummy_engine = ffi.verify( return 1; } """, - libraries=["crypto", "ssl"], + libraries=libraries ) -- cgit v1.2.3 From ae2138aaa2049cd066a3679ff4d82f57b6843d61 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Jan 2014 22:19:47 -0600 Subject: add a hyphen to please the spellcheck gods --- docs/hazmat/backends/openssl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index b7133deb..8eb02ea4 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -28,7 +28,7 @@ The `OpenSSL`_ C library. OS Random Engine ---------------- -OpenSSL uses a userspace CSPRNG that is seeded from system random ( +OpenSSL uses a user-space CSPRNG that is seeded from system random ( ``/dev/urandom`` or ``CryptGenRandom``). This CSPRNG is not reseeded automatically when a process calls ``fork()``. This can result in situations where two different processes can return similar or identical keys and -- cgit v1.2.3 From 16e5e4d2659a0e6cbea44f561914142c80554a73 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 30 Jan 2014 09:43:30 -0600 Subject: address review comments on osrandom engine, reorganize some code --- .../hazmat/bindings/openssl/osrand_engine.py | 137 ++++++++++++--------- docs/hazmat/backends/openssl.rst | 2 +- 2 files changed, 79 insertions(+), 60 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/osrand_engine.py b/cryptography/hazmat/bindings/openssl/osrand_engine.py index bca2d79d..a04daed1 100644 --- a/cryptography/hazmat/bindings/openssl/osrand_engine.py +++ b/cryptography/hazmat/bindings/openssl/osrand_engine.py @@ -32,35 +32,60 @@ int Cryptography_add_osrandom_engine(void); MACROS = """ """ -CUSTOMIZATIONS = """ -static const char *Cryptography_osrandom_engine_id= "osrandom"; -static const char *Cryptography_osrandom_engine_name = "osrandom_engine"; +WIN32_CUSTOMIZATIONS = """ +static HCRYPTPROV hCryptProv = 0; -#ifndef _WIN32 -static int urandom_fd = -1; +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) { - ssize_t n; - while (0 < size) { - do { - n = read(urandom_fd, buffer, (size_t)size); - } while (n < 0 && errno == EINTR); - if (n <= 0) { + size_t chunk; + + if (hCryptProv == 0) { + return 0; + } + + while (size > 0) { + chunk = size; + if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer)) { + ERR_put_error(ERR_LIB_RAND, 0, ERR_R_RAND_LIB, "osrandom.py", 0); return 0; } - buffer += n; - size -= n; + buffer += chunk; + size -= chunk; } 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 (urandom_fd == -1) { + if (hCryptProv == 0) { return 0; } else { return 1; } } +""" + +POSIX_CUSTOMIZATIONS = """ +static int urandom_fd = -1; static int osrandom_init(ENGINE *e) { if (urandom_fd > -1) { @@ -77,78 +102,71 @@ static int osrandom_init(ENGINE *e) { } } +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) { - urandom_fd = -1; return 0; } else { - urandom_fd = -1; return 1; } } -#endif -#ifdef _WIN32 -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 { +static int osrandom_rand_status(void) { + if (urandom_fd == -1) { return 0; + } else { + return 1; } } +""" -static int osrandom_rand_bytes(unsigned char *buffer, int size) { - size_t chunk; - - if (hCryptProv == 0) { - return 0; - } - - while (size > 0) { - chunk = size; - if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer)) { - return 0; - } - buffer += chunk; - size -= chunk; - } - return 1; -} +CUSTOMIZATIONS = """ +static const char *Cryptography_osrandom_engine_id = "osrandom"; +static const char *Cryptography_osrandom_engine_name = "osrandom_engine"; -static int osrandom_finish(ENGINE *e) { - if (CryptReleaseContext(hCryptProv, 0)) { - hCryptProv = 0; - return 1; - } else { - return 0; - } -} +#if defined(_WIN32) +""" + WIN32_CUSTOMIZATIONS + """ +#else +""" + POSIX_CUSTOMIZATIONS + """ +#endif -static int osrandom_rand_status(void) { - if (hCryptProv == 0) { - return 0; +/* 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 1; + return res; } } -#endif /* MS_WINDOWS */ static RAND_METHOD osrandom_rand = { NULL, osrandom_rand_bytes, NULL, NULL, - osrandom_rand_bytes, + osrandom_pseudo_rand_bytes, osrandom_rand_status, }; @@ -162,6 +180,7 @@ int Cryptography_add_osrandom_engine(void) { !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)) { diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 8eb02ea4..79c58857 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -55,7 +55,7 @@ utilizes the `Yarrow`_ algorithm. On Windows ``CryptGenRandom`` is backed by `Fortuna`_. Linux uses its own PRNG design. ``/dev/urandom`` is a non-blocking source seeded -from the ``/dev/random`` pool. +from the same pool as ``/dev/random``. .. _`OpenSSL`: https://www.openssl.org/ -- cgit v1.2.3 From 8042b2988d71d3675e06d25416e285215ae98636 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 31 Jan 2014 10:44:36 -0600 Subject: more explanation of what an active osrandom engine means --- docs/hazmat/backends/openssl.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 79c58857..81361f5a 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -41,10 +41,16 @@ its entropy from ``/dev/urandom`` on UNIX-like operating systems and uses allows us to avoid potential issues with `initializing the RNG`_ as well as protecting us from the ``fork()`` weakness. -This engine is **active** by default when importing the OpenSSL backend. It is -added to the engine list but **not activated** if you only import the binding. -If you wish to deactivate it call ``unregister_osrandom_engine()`` on the -backend object. +This engine is **active** by default when importing the OpenSSL backend. When +active this engine will be used to generate all the random data OpenSSL +requests. + +If you wish to deactivate the engine you may call +``unregister_osrandom_engine()`` on the backend object. + +When importing only the binding it is added to the engine list but +**not activated**. + OS Random Sources ----------------- -- cgit v1.2.3 From d52b89b4e881639bc68d9c30983e08a1b8085be8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 31 Jan 2014 10:57:17 -0600 Subject: change register/unregister to activate/deactivate --- cryptography/hazmat/backends/openssl/backend.py | 12 ++++---- docs/hazmat/backends/openssl.rst | 13 ++++---- tests/hazmat/backends/test_openssl.py | 40 ++++++++++++------------- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 99d97b7f..afd45e89 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -58,9 +58,9 @@ class Backend(object): self._cipher_registry = {} self._register_default_ciphers() - self.register_osrandom_engine() + self.activate_osrandom_engine() - def unregister_osrandom_engine(self): + def deactivate_osrandom_engine(self): e = self._lib.ENGINE_get_default_RAND() if e != self._ffi.NULL: name = self._lib.ENGINE_get_name(e) @@ -72,19 +72,19 @@ class Backend(object): res = self._lib.ENGINE_finish(e) assert res == 1 - def register_osrandom_engine(self): + def activate_osrandom_engine(self): current_rand = self._lib.ENGINE_get_default_RAND() if current_rand != self._ffi.NULL: name = self._lib.ENGINE_get_name(current_rand) assert name != self._ffi.NULL if name != self._lib.Cryptography_osrandom_engine_name: - self._register_osrandom_engine() + self._activate_osrandom_engine() res = self._lib.ENGINE_finish(current_rand) assert res == 1 else: - self._register_osrandom_engine() + self._activate_osrandom_engine() - def _register_osrandom_engine(self): + def _activate_osrandom_engine(self): e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) assert e != self._ffi.NULL res = self._lib.ENGINE_init(e) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 81361f5a..1d40b93c 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -13,14 +13,14 @@ The `OpenSSL`_ C library. The string name of this backend: ``"openssl"`` - .. method:: register_osrandom_engine() + .. method:: activate_osrandom_engine() - Registers the OS random engine as default. This will effectively - disable OpenSSL's default CSPRNG. + Activates the OS random engine. This will effectively disable OpenSSL's + default CSPRNG. - .. method:: unregister_osrandom_engine() + .. method:: deactivate_osrandom_engine() - Unregisters the OS random engine if it is default. This will restore + Deactivates the OS random engine if it is default. This will restore the default OpenSSL CSPRNG. If the OS random engine is not the default engine (e.g. if another engine is set as default) nothing will be changed. @@ -45,9 +45,6 @@ This engine is **active** by default when importing the OpenSSL backend. When active this engine will be used to generate all the random data OpenSSL requests. -If you wish to deactivate the engine you may call -``unregister_osrandom_engine()`` on the backend object. - When importing only the binding it is added to the engine list but **not activated**. diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index ea716204..daae2065 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -88,7 +88,7 @@ dummy_engine = ffi.verify( ) -def register_dummy_engine(): +def activate_dummy_engine(): current_rand = backend._lib.ENGINE_get_default_RAND() assert current_rand != backend._ffi.NULL name = backend._lib.ENGINE_get_name(current_rand) @@ -110,7 +110,7 @@ def register_dummy_engine(): backend._lib.RAND_cleanup() -def unregister_dummy_engine(): +def deactivate_dummy_engine(): e = backend._lib.ENGINE_get_default_RAND() if e != backend._ffi.NULL: name = backend._lib.ENGINE_get_name(e) @@ -233,77 +233,77 @@ class TestOpenSSLRandomEngine(object): def teardown_method(self, method): # we need to reset state to being default. backend is a shared global # for all these tests. - unregister_dummy_engine() - backend.register_osrandom_engine() + deactivate_dummy_engine() + backend.activate_osrandom_engine() current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) assert name == backend._lib.Cryptography_osrandom_engine_name - def test_register_osrandom_already_default(self): + def test_activate_osrandom_already_default(self): e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 - backend.register_osrandom_engine() + backend.activate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 - def test_unregister_osrandom_engine_nothing_registered(self): - backend.unregister_osrandom_engine() + def test_deactivate_osrandom_engine_nothing_registered(self): + backend.deactivate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() assert e == backend._ffi.NULL - backend.unregister_osrandom_engine() + backend.deactivate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() assert e == backend._ffi.NULL - def test_unregister_osrandom_engine(self): + def test_deactivate_osrandom_engine(self): e = backend._lib.ENGINE_get_default_RAND() assert e != backend._ffi.NULL name = backend._lib.ENGINE_get_name(e) assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 - backend.unregister_osrandom_engine() + backend.deactivate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() assert e == backend._ffi.NULL - def test_register_osrandom_no_default(self): - backend.unregister_osrandom_engine() + def test_activate_osrandom_no_default(self): + backend.deactivate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() assert e == backend._ffi.NULL - backend.register_osrandom_engine() + backend.activate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 - def test_unregister_osrandom_other_engine_default(self): - register_dummy_engine() + def test_deactivate_osrandom_other_engine_default(self): + activate_dummy_engine() default = backend._lib.ENGINE_get_default_RAND() default_name = backend._lib.ENGINE_get_name(default) assert default_name == dummy_engine.Cryptography_faux_engine_name res = backend._lib.ENGINE_finish(default) assert res == 1 - backend.unregister_osrandom_engine() + backend.deactivate_osrandom_engine() current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) assert name == dummy_engine.Cryptography_faux_engine_name res = backend._lib.ENGINE_finish(current_default) assert res == 1 - def test_register_osrandom_other_engine_default(self): - register_dummy_engine() + def test_activate_osrandom_other_engine_default(self): + activate_dummy_engine() default = backend._lib.ENGINE_get_default_RAND() default_name = backend._lib.ENGINE_get_name(default) assert default_name == dummy_engine.Cryptography_faux_engine_name res = backend._lib.ENGINE_finish(default) assert res == 1 - backend.register_osrandom_engine() + backend.activate_osrandom_engine() current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) assert name == backend._lib.Cryptography_osrandom_engine_name -- cgit v1.2.3 From e035ba978bf81c9dc17c33d7a8c6d61082ac4292 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 2 Feb 2014 12:46:47 -0600 Subject: add catastrophic failure check to tests --- tests/hazmat/backends/test_openssl.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index daae2065..cef28af0 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -239,6 +239,13 @@ class TestOpenSSLRandomEngine(object): name = backend._lib.ENGINE_get_name(current_default) assert name == backend._lib.Cryptography_osrandom_engine_name + def test_osrandom_sanity_check(self): + # This test serves as a check against catastrophic failure. + buf = backend._ffi.new("char[]", 500) + res = backend._lib.RAND_bytes(buf, 500) + assert res == 1 + assert backend._ffi.buffer(buf)[:] != "\x00" * 500 + def test_activate_osrandom_already_default(self): e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) -- cgit v1.2.3 From b930b1289a5ba729c26a8fd25daddc90f497ddf9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Feb 2014 08:50:54 -0600 Subject: close the fd if fcntl fails --- cryptography/hazmat/bindings/openssl/osrand_engine.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cryptography/hazmat/bindings/openssl/osrand_engine.py b/cryptography/hazmat/bindings/openssl/osrand_engine.py index a04daed1..2313a61f 100644 --- a/cryptography/hazmat/bindings/openssl/osrand_engine.py +++ b/cryptography/hazmat/bindings/openssl/osrand_engine.py @@ -94,6 +94,7 @@ static int osrandom_init(ENGINE *e) { urandom_fd = open("/dev/urandom", O_RDONLY); if (urandom_fd > -1) { if (fcntl(urandom_fd, F_SETFD, FD_CLOEXEC) == -1) { + osrandom_finish(e); return 0; } return 1; -- cgit v1.2.3 From 8d4d9ff129e12bd02f0a88ddb359cf228bcf1e4e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Feb 2014 09:18:10 -0600 Subject: cryptgenrandom returns all requested bytes or errors, so no loop required --- cryptography/hazmat/bindings/openssl/osrand_engine.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/osrand_engine.py b/cryptography/hazmat/bindings/openssl/osrand_engine.py index 2313a61f..4163668b 100644 --- a/cryptography/hazmat/bindings/openssl/osrand_engine.py +++ b/cryptography/hazmat/bindings/openssl/osrand_engine.py @@ -48,20 +48,13 @@ static int osrandom_init(ENGINE *e) { } static int osrandom_rand_bytes(unsigned char *buffer, int size) { - size_t chunk; - if (hCryptProv == 0) { return 0; } - while (size > 0) { - chunk = size; - if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer)) { - ERR_put_error(ERR_LIB_RAND, 0, ERR_R_RAND_LIB, "osrandom.py", 0); - return 0; - } - buffer += chunk; - size -= chunk; + if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) { + ERR_put_error(ERR_LIB_RAND, 0, ERR_R_RAND_LIB, "osrandom.py", 0); + return 0; } return 1; } -- cgit v1.2.3 From 34630206c105bbced93755f2e869b1fa3485d8cb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Feb 2014 09:29:52 -0600 Subject: forward declaration woo --- cryptography/hazmat/bindings/openssl/osrand_engine.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cryptography/hazmat/bindings/openssl/osrand_engine.py b/cryptography/hazmat/bindings/openssl/osrand_engine.py index 4163668b..5c5661b9 100644 --- a/cryptography/hazmat/bindings/openssl/osrand_engine.py +++ b/cryptography/hazmat/bindings/openssl/osrand_engine.py @@ -80,6 +80,8 @@ static int osrandom_rand_status(void) { 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; -- cgit v1.2.3 From 57b325e90bd20156fcbd64a57961c2a760ca28bb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Feb 2014 16:03:10 -0600 Subject: rename osrand_engine to osrandom_engine --- cryptography/hazmat/bindings/openssl/binding.py | 2 +- .../hazmat/bindings/openssl/osrand_engine.py | 194 --------------------- .../hazmat/bindings/openssl/osrandom_engine.py | 194 +++++++++++++++++++++ 3 files changed, 195 insertions(+), 195 deletions(-) delete mode 100644 cryptography/hazmat/bindings/openssl/osrand_engine.py create mode 100644 cryptography/hazmat/bindings/openssl/osrandom_engine.py diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py index 843bd3ea..84bfacbc 100644 --- a/cryptography/hazmat/bindings/openssl/binding.py +++ b/cryptography/hazmat/bindings/openssl/binding.py @@ -60,7 +60,7 @@ class Binding(object): "nid", "objects", "opensslv", - "osrand_engine", + "osrandom_engine", "pem", "pkcs7", "pkcs12", diff --git a/cryptography/hazmat/bindings/openssl/osrand_engine.py b/cryptography/hazmat/bindings/openssl/osrand_engine.py deleted file mode 100644 index 5c5661b9..00000000 --- a/cryptography/hazmat/bindings/openssl/osrand_engine.py +++ /dev/null @@ -1,194 +0,0 @@ -# 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 -#else -#include -#include -#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) { - if (fcntl(urandom_fd, F_SETFD, 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 = {} diff --git a/cryptography/hazmat/bindings/openssl/osrandom_engine.py b/cryptography/hazmat/bindings/openssl/osrandom_engine.py new file mode 100644 index 00000000..5c5661b9 --- /dev/null +++ b/cryptography/hazmat/bindings/openssl/osrandom_engine.py @@ -0,0 +1,194 @@ +# 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 +#else +#include +#include +#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) { + if (fcntl(urandom_fd, F_SETFD, 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 = {} -- cgit v1.2.3 From 1389acbfa1fb90cdabe93810c30b481e9d3e4042 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Feb 2014 16:04:39 -0600 Subject: assert the right thing --- tests/hazmat/backends/test_openssl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 046ff3e1..ef7560f7 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -92,7 +92,7 @@ def activate_dummy_engine(): assert current_rand != backend._ffi.NULL name = backend._lib.ENGINE_get_name(current_rand) assert name != backend._ffi.NULL - assert name != dummy_engine.Cryptography_faux_engine_id + assert name != dummy_engine.Cryptography_faux_engine_name res = backend._lib.ENGINE_finish(current_rand) assert res == 1 e = backend._lib.ENGINE_by_id(dummy_engine.Cryptography_faux_engine_id) -- cgit v1.2.3 From 27864789563c90edb42772a9af1602be87029abc Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Feb 2014 16:19:37 -0600 Subject: add some more comments to clarify what the ENGINE_ calls in backend do --- cryptography/hazmat/backends/openssl/backend.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 4dd544cf..31ffe0d1 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -61,34 +61,48 @@ class Backend(object): self.activate_osrandom_engine() def deactivate_osrandom_engine(self): + # obtains a new structural reference e = self._lib.ENGINE_get_default_RAND() if e != self._ffi.NULL: + # this obtains the name of the engine but does not obtain a + # structural or functional reference name = self._lib.ENGINE_get_name(e) assert name != self._ffi.NULL if name == self._lib.Cryptography_osrandom_engine_name: + # removes the engine provided from the list of available RAND + # engines. self._lib.ENGINE_unregister_RAND(e) # this resets 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): + # obtains a new structural reference current_rand = self._lib.ENGINE_get_default_RAND() if current_rand != self._ffi.NULL: + # this obtains the name of the engine but does not obtain a + # structural or functional reference name = self._lib.ENGINE_get_name(current_rand) assert name != self._ffi.NULL if name != self._lib.Cryptography_osrandom_engine_name: self._activate_osrandom_engine() + # decrement the structural reference from get_default_RAND res = self._lib.ENGINE_finish(current_rand) assert res == 1 else: self._activate_osrandom_engine() def _activate_osrandom_engine(self): + # 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 @@ -97,7 +111,7 @@ class Backend(object): # decrement the functional ref incremented by ENGINE_init res = self._lib.ENGINE_finish(e) assert res == 1 - # this resets the RNG to use the new engine + # Reset the RNG to use the new engine self._lib.RAND_cleanup() def openssl_version_text(self): -- cgit v1.2.3 From d258222091c9ac2d5a701debca356e3d9a3f8559 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 5 Feb 2014 16:21:19 -0600 Subject: remove deactivate and replace with activate_builtin_random --- cryptography/hazmat/backends/openssl/backend.py | 33 +---- docs/hazmat/backends/openssl.rst | 7 +- tests/hazmat/backends/test_openssl.py | 160 ++---------------------- 3 files changed, 21 insertions(+), 179 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index f4b5c3ac..83a65b32 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -60,41 +60,20 @@ class Backend(object): self._register_default_ciphers() self.activate_osrandom_engine() - def deactivate_osrandom_engine(self): + def activate_builtin_random(self): # obtains a new structural reference e = self._lib.ENGINE_get_default_RAND() if e != self._ffi.NULL: - # this obtains the name of the engine but does not obtain a - # structural or functional reference - name = self._lib.ENGINE_get_name(e) - assert name != self._ffi.NULL - if name == self._lib.Cryptography_osrandom_engine_name: - # removes the engine provided from the list of available RAND - # engines. - self._lib.ENGINE_unregister_RAND(e) - # this resets the RNG to use the new engine - self._lib.RAND_cleanup() + self._lib.ENGINE_unregister_RAND(e) + # this resets 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): - # obtains a new structural reference - current_rand = self._lib.ENGINE_get_default_RAND() - if current_rand != self._ffi.NULL: - # this obtains the name of the engine but does not obtain a - # structural or functional reference - name = self._lib.ENGINE_get_name(current_rand) - assert name != self._ffi.NULL - if name != self._lib.Cryptography_osrandom_engine_name: - self._activate_osrandom_engine() - # decrement the structural reference from get_default_RAND - res = self._lib.ENGINE_finish(current_rand) - assert res == 1 - else: - self._activate_osrandom_engine() - - 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) diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index f7d6b710..ea72af96 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -27,12 +27,9 @@ The `OpenSSL`_ C library. Activates the OS random engine. This will effectively disable OpenSSL's default CSPRNG. - .. method:: deactivate_osrandom_engine() + .. method:: activate_builtin_random() - Deactivates the OS random engine if it is default. This will restore - the default OpenSSL CSPRNG. If the OS random engine is not the default - engine (e.g. if another engine is set as default) nothing will be - changed. + This will activate the default OpenSSL CSPRNG. OS Random Engine ---------------- diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 1fd513d5..b24808df 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -11,10 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - -import cffi - import pytest from cryptography import utils @@ -26,101 +22,6 @@ from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC -if sys.platform != "win32": - libraries = ["crypto", "ssl"] -else: # pragma: no cover - libraries = ["libeay32", "ssleay32", "advapi32"] - -ffi = cffi.FFI() - -ffi.cdef(""" -static const char *const Cryptography_faux_engine_name; -static const char *const Cryptography_faux_engine_id; -int Cryptography_add_faux_engine(void); -""") -dummy_engine = ffi.verify( - source=""" - #include - #include - static const char *const Cryptography_faux_engine_name="faux_engine"; - static const char *const Cryptography_faux_engine_id="faux"; - static int faux_bytes(unsigned char *buffer, int size) { - memset(buffer, 1, size); - return 1; - } - static int faux_status(void) { return 1; } - static int faux_init(ENGINE *e) { return 1; } - static int faux_finish(ENGINE *e) { return 1; } - static RAND_METHOD faux_rand = { - NULL, - faux_bytes, - NULL, - NULL, - faux_bytes, - faux_status, - }; - - int Cryptography_add_faux_engine(void) { - ENGINE *e = ENGINE_new(); - if (e == NULL) { - return 0; - } - if(!ENGINE_set_id(e, Cryptography_faux_engine_id) || - !ENGINE_set_name(e, Cryptography_faux_engine_name) || - !ENGINE_set_RAND(e, &faux_rand) || - !ENGINE_set_init_function(e, faux_init) || - !ENGINE_set_finish_function(e, faux_finish)) { - return 0; - } - if (!ENGINE_add(e)) { - ENGINE_free(e); - return 0; - } - if (!ENGINE_free(e)) { - return 0; - } - - return 1; - } - """, - libraries=libraries -) - - -def activate_dummy_engine(): - current_rand = backend._lib.ENGINE_get_default_RAND() - assert current_rand != backend._ffi.NULL - name = backend._lib.ENGINE_get_name(current_rand) - assert name != backend._ffi.NULL - assert name != dummy_engine.Cryptography_faux_engine_name - res = backend._lib.ENGINE_finish(current_rand) - assert res == 1 - e = backend._lib.ENGINE_by_id(dummy_engine.Cryptography_faux_engine_id) - assert e != backend._ffi.NULL - res = backend._lib.ENGINE_init(e) - assert res == 1 - res = backend._lib.ENGINE_set_default_RAND(e) - assert res == 1 - res = backend._lib.ENGINE_finish(e) - assert res == 1 - res = backend._lib.ENGINE_free(e) - assert res == 1 - # this resets the RNG to use the new engine - backend._lib.RAND_cleanup() - - -def deactivate_dummy_engine(): - e = backend._lib.ENGINE_get_default_RAND() - if e != backend._ffi.NULL: - name = backend._lib.ENGINE_get_name(e) - assert name != backend._ffi.NULL - if name == dummy_engine.Cryptography_faux_engine_name: - backend._lib.ENGINE_unregister_RAND(e) - backend._lib.RAND_cleanup() - res = backend._lib.ENGINE_finish(e) - assert res == 1 - - @utils.register_interface(interfaces.Mode) class DummyMode(object): name = "dummy-mode" @@ -263,16 +164,9 @@ class TestOpenSSL(object): class TestOpenSSLRandomEngine(object): - @classmethod - def setup_class(cls): - # add the faux engine to the list of available engines - res = dummy_engine.Cryptography_add_faux_engine() - assert res == 1 - def teardown_method(self, method): # we need to reset state to being default. backend is a shared global # for all these tests. - deactivate_dummy_engine() backend.activate_osrandom_engine() current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) @@ -298,60 +192,32 @@ class TestOpenSSLRandomEngine(object): res = backend._lib.ENGINE_free(e) assert res == 1 - def test_deactivate_osrandom_engine_nothing_registered(self): - backend.deactivate_osrandom_engine() + def test_activate_osrandom_no_default(self): + backend.activate_builtin_random() e = backend._lib.ENGINE_get_default_RAND() assert e == backend._ffi.NULL - backend.deactivate_osrandom_engine() + backend.activate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() - assert e == backend._ffi.NULL + name = backend._lib.ENGINE_get_name(e) + assert name == backend._lib.Cryptography_osrandom_engine_name + res = backend._lib.ENGINE_free(e) + assert res == 1 - def test_deactivate_osrandom_engine(self): + def test_activate_builtin_random(self): e = backend._lib.ENGINE_get_default_RAND() assert e != backend._ffi.NULL name = backend._lib.ENGINE_get_name(e) assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 - backend.deactivate_osrandom_engine() + backend.activate_builtin_random() e = backend._lib.ENGINE_get_default_RAND() assert e == backend._ffi.NULL - def test_activate_osrandom_no_default(self): - backend.deactivate_osrandom_engine() + def test_activate_builtin_random_already_active(self): + backend.activate_builtin_random() e = backend._lib.ENGINE_get_default_RAND() assert e == backend._ffi.NULL - backend.activate_osrandom_engine() + backend.activate_builtin_random() e = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(e) - assert name == backend._lib.Cryptography_osrandom_engine_name - res = backend._lib.ENGINE_free(e) - assert res == 1 - - def test_deactivate_osrandom_other_engine_default(self): - activate_dummy_engine() - default = backend._lib.ENGINE_get_default_RAND() - default_name = backend._lib.ENGINE_get_name(default) - assert default_name == dummy_engine.Cryptography_faux_engine_name - res = backend._lib.ENGINE_finish(default) - assert res == 1 - backend.deactivate_osrandom_engine() - current_default = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(current_default) - assert name == dummy_engine.Cryptography_faux_engine_name - res = backend._lib.ENGINE_finish(current_default) - assert res == 1 - - def test_activate_osrandom_other_engine_default(self): - activate_dummy_engine() - default = backend._lib.ENGINE_get_default_RAND() - default_name = backend._lib.ENGINE_get_name(default) - assert default_name == dummy_engine.Cryptography_faux_engine_name - res = backend._lib.ENGINE_finish(default) - assert res == 1 - backend.activate_osrandom_engine() - current_default = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(current_default) - assert name == backend._lib.Cryptography_osrandom_engine_name - res = backend._lib.ENGINE_finish(current_default) - assert res == 1 + assert e == backend._ffi.NULL -- cgit v1.2.3 From f146d45288fa821ffba6dd0705be75acaf61e8e9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 5 Feb 2014 16:53:21 -0600 Subject: get urandom fd flag and bitwise OR it with FD_CLOEXEC. comment update --- cryptography/hazmat/bindings/openssl/osrandom_engine.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/osrandom_engine.py b/cryptography/hazmat/bindings/openssl/osrandom_engine.py index 5c5661b9..6e7e172e 100644 --- a/cryptography/hazmat/bindings/openssl/osrandom_engine.py +++ b/cryptography/hazmat/bindings/openssl/osrandom_engine.py @@ -88,7 +88,11 @@ static int osrandom_init(ENGINE *e) { } urandom_fd = open("/dev/urandom", O_RDONLY); if (urandom_fd > -1) { - if (fcntl(urandom_fd, F_SETFD, FD_CLOEXEC) == -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; } @@ -147,7 +151,7 @@ static const char *Cryptography_osrandom_engine_name = "osrandom_engine"; #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. */ + -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) { -- cgit v1.2.3 From 089dded7dac4f2ec50d469f70eff6b66f5dcc321 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 5 Feb 2014 17:00:46 -0600 Subject: remove unregisters from wordlist as it's not in the docs now --- docs/spelling_wordlist.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index acb50ff6..cf421ea6 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -28,4 +28,3 @@ Changelog Docstrings Fernet Schneier -Unregisters -- cgit v1.2.3 From b02ed2aa7670f12c4d507bee1d33483f0f7d66c9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 5 Feb 2014 17:05:56 -0600 Subject: add os random engine to changelog --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index e322b145..4d459bd9 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,6 +17,7 @@ Changelog * Added :class:`~cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC`. * Added :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF`. * Added :doc:`/hazmat/backends/multibackend`. +* Set default random for the :doc:`/hazmat/backends/openssl` to the OS random engine. 0.1 - 2014-01-08 ~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From f389f84fc7bb4d20ac00c571f221185d5b4874a8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 5 Feb 2014 17:06:10 -0600 Subject: improve comments --- cryptography/hazmat/backends/openssl/backend.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 83a65b32..6da90cef 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -61,11 +61,11 @@ class Backend(object): self.activate_osrandom_engine() def activate_builtin_random(self): - # obtains a new structural reference + # Obtain a new structural reference. e = self._lib.ENGINE_get_default_RAND() if e != self._ffi.NULL: self._lib.ENGINE_unregister_RAND(e) - # this resets the RNG to use the new engine + # 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) @@ -84,13 +84,13 @@ class Backend(object): # 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 + # 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 + # 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 + # Reset the RNG to use the new engine. self._lib.RAND_cleanup() def openssl_version_text(self): -- cgit v1.2.3