Merge branch 'master' into urandom-engine

* master: (169 commits)
  Make just one call to ffi.cdef for most of the definitions
  Use pytest.fixture for backends
  drop to >= 0.8 to make pypy happy
  change to anonymous enum
  require cffi >= 0.8.1
  remove extraneous spaces
  add hmac to commoncrypto binding
  bytes byte back
  add check to confirm we've loaded error strings
  Bind all the PEM errors
  Spelling!
  oops, bytes plz
  don't leak a context in the test
  add tests to the openssl backend to verify that we've registered
  Nonsense I think we need.
  This is a dep
  init the ssl library in the backend
  Actuall install a thing
  Try to run the spellchecker on travis
  Use a normal quote here, not sure where the smart quote came from
  ...

Conflicts:
	cryptography/hazmat/bindings/openssl/binding.py
	tests/hazmat/backends/test_openssl.py
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 07ee58c..ec2824d 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -52,6 +52,47 @@
 
         self._cipher_registry = {}
         self._register_default_ciphers()
+        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)
+                # this resets the RNG to use the new engine
+                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:
+                self._register_osrandom_engine()
+            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)
+        assert res == 1
+        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
+        # this resets 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 8a4e1dd..2419044 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -55,6 +55,7 @@
         "nid",
         "objects",
         "opensslv",
+        "osrand_engine",
         "pem",
         "pkcs7",
         "pkcs12",
@@ -80,6 +81,8 @@
         cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
                                      _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE,
                                      ["crypto", "ssl"])
+        res = cls.lib.Cryptography_add_osrandom_engine()
+        assert res == 1
 
     @classmethod
     def is_available(cls):
diff --git a/cryptography/hazmat/bindings/openssl/osrand_engine.py b/cryptography/hazmat/bindings/openssl/osrand_engine.py
new file mode 100644
index 0000000..bca2d79
--- /dev/null
+++ b/cryptography/hazmat/bindings/openssl/osrand_engine.py
@@ -0,0 +1,179 @@
+# 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 = """
+"""
+
+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;
+        }
+        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) {
+        if (fcntl(urandom_fd, F_SETFD, FD_CLOEXEC) == -1) {
+            return 0;
+        }
+        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) {
+        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 {
+        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/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 2a32992..51eb408 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,96 @@
 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);
+""")
+dummy_engine = ffi.verify(
+    source="""
+        #include <openssl/engine.h>
+        #include <string.h>
+        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=["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
+    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 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)
+            backend._lib.RAND_cleanup()
+        res = backend._lib.ENGINE_finish(e)
+        assert res == 1
+
+
 @utils.register_interface(interfaces.Mode)
 class DummyMode(object):
     name = "dummy-mode"
@@ -113,3 +205,100 @@
             b"error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:"
             b"data not multiple of block length"
         )
+
+    # 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)
+        assert res == 1
+
+
+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.
+        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
+
+    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)
+        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)
+        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
+        backend.unregister_osrandom_engine()
+        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)
+        assert res == 1
+        backend.unregister_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()
+        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)
+        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)
+        assert default_name == dummy_engine.Cryptography_faux_engine_name
+        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)
+        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()
+        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()
+        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