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