Merge pull request #577 from public/backend-rsa-interface

RSABackend interface
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 74faee5..6da90ce 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -58,6 +58,40 @@
 
         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 cde3bdb..714ecc0 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -60,6 +60,7 @@
         "nid",
         "objects",
         "opensslv",
+        "osrandom_engine",
         "pem",
         "pkcs7",
         "pkcs12",
@@ -86,19 +87,23 @@
         if cls.ffi is not None and cls.lib is not None:
             return
 
-        # platform check to set the right library names
+        # OpenSSL goes by a different library name on different operating
+        # systems.
         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):
-        # OpenSSL is the only binding so for now it must always be available
+        # For now, OpenSSL is considered our "default" binding, so we treat it
+        # as always available.
         return True
 
     @classmethod
@@ -112,15 +117,15 @@
                     cls._lock_cb
                 )
 
-            # use Python's implementation if available
-
+            # Use Python's implementation if available, importing _ssl triggers
+            # the setup for this.
             __import__("_ssl")
 
             if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL:
                 return
 
-            # otherwise setup our version
-
+            # If nothing else has setup a locking callback already, we set up
+            # our own
             num_locks = cls.lib.CRYPTO_num_locks()
             cls._locks = [threading.Lock() for n in range(num_locks)]
 
diff --git a/cryptography/hazmat/bindings/openssl/osrandom_engine.py b/cryptography/hazmat/bindings/openssl/osrandom_engine.py
new file mode 100644
index 0000000..23f2e17
--- /dev/null
+++ b/cryptography/hazmat/bindings/openssl/osrandom_engine.py
@@ -0,0 +1,205 @@
+# 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_engine.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_engine.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)s
+#else
+%(POSIX_CUSTOMIZATIONS)s
+#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;
+}
+""" % {
+    "WIN32_CUSTOMIZATIONS": WIN32_CUSTOMIZATIONS,
+    "POSIX_CUSTOMIZATIONS": POSIX_CUSTOMIZATIONS,
+}
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py
index 2b4e54f..6c5795b 100644
--- a/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/cryptography/hazmat/bindings/openssl/ssl.py
@@ -268,6 +268,10 @@
 const SSL_METHOD *TLSv1_server_method(void);
 const SSL_METHOD *TLSv1_client_method(void);
 
+const SSL_METHOD *DTLSv1_method(void);
+const SSL_METHOD *DTLSv1_server_method(void);
+const SSL_METHOD *DTLSv1_client_method(void);
+
 const SSL_METHOD *SSLv23_method(void);
 const SSL_METHOD *SSLv23_server_method(void);
 const SSL_METHOD *SSLv23_client_method(void);
diff --git a/cryptography/hazmat/primitives/asymmetric/__init__.py b/cryptography/hazmat/primitives/asymmetric/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cryptography/hazmat/primitives/asymmetric/__init__.py
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
new file mode 100644
index 0000000..1b33eaa
--- /dev/null
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -0,0 +1,149 @@
+# 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.
+
+from __future__ import absolute_import, division, print_function
+
+import sys
+
+import six
+
+from cryptography import utils
+from cryptography.hazmat.primitives import interfaces
+
+
+def _bit_length(x):
+    if sys.version_info >= (2, 7):
+        return x.bit_length()
+    else:
+        return len(bin(x)) - (2 + (x <= 0))
+
+
+@utils.register_interface(interfaces.RSAPublicKey)
+class RSAPublicKey(object):
+    def __init__(self, public_exponent, modulus):
+        if (
+            not isinstance(public_exponent, six.integer_types) or
+            not isinstance(modulus, six.integer_types)
+        ):
+            raise TypeError("RSAPublicKey arguments must be integers")
+
+        if modulus < 3:
+            raise ValueError("modulus must be >= 3")
+
+        if public_exponent < 3 or public_exponent >= modulus:
+            raise ValueError("public_exponent must be >= 3 and < modulus")
+
+        if public_exponent & 1 == 0:
+            raise ValueError("public_exponent must be odd")
+
+        self._public_exponent = public_exponent
+        self._modulus = modulus
+
+    @property
+    def key_size(self):
+        return _bit_length(self.modulus)
+
+    @property
+    def public_exponent(self):
+        return self._public_exponent
+
+    @property
+    def modulus(self):
+        return self._modulus
+
+    @property
+    def e(self):
+        return self.public_exponent
+
+    @property
+    def n(self):
+        return self.modulus
+
+
+@utils.register_interface(interfaces.RSAPrivateKey)
+class RSAPrivateKey(object):
+    def __init__(self, p, q, private_exponent, public_exponent, modulus):
+        if (
+            not isinstance(p, six.integer_types) or
+            not isinstance(q, six.integer_types) or
+            not isinstance(private_exponent, six.integer_types) or
+            not isinstance(public_exponent, six.integer_types) or
+            not isinstance(modulus, six.integer_types)
+        ):
+            raise TypeError("RSAPrivateKey arguments must be integers")
+
+        if modulus < 3:
+            raise ValueError("modulus must be >= 3")
+
+        if p >= modulus:
+            raise ValueError("p must be < modulus")
+
+        if q >= modulus:
+            raise ValueError("q must be < modulus")
+
+        if private_exponent >= modulus:
+            raise ValueError("private_exponent must be < modulus")
+
+        if public_exponent < 3 or public_exponent >= modulus:
+            raise ValueError("public_exponent must be >= 3 and < modulus")
+
+        if public_exponent & 1 == 0:
+            raise ValueError("public_exponent must be odd")
+
+        if p * q != modulus:
+            raise ValueError("p*q must equal modulus")
+
+        self._p = p
+        self._q = q
+        self._private_exponent = private_exponent
+        self._public_exponent = public_exponent
+        self._modulus = modulus
+
+    @property
+    def key_size(self):
+        return _bit_length(self.modulus)
+
+    def public_key(self):
+        return RSAPublicKey(self.public_exponent, self.modulus)
+
+    @property
+    def p(self):
+        return self._p
+
+    @property
+    def q(self):
+        return self._q
+
+    @property
+    def private_exponent(self):
+        return self._private_exponent
+
+    @property
+    def public_exponent(self):
+        return self._public_exponent
+
+    @property
+    def modulus(self):
+        return self._modulus
+
+    @property
+    def d(self):
+        return self.private_exponent
+
+    @property
+    def e(self):
+        return self.public_exponent
+
+    @property
+    def n(self):
+        return self.modulus
diff --git a/docs/changelog.rst b/docs/changelog.rst
index e322b14..4d459bd 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -17,6 +17,7 @@
 * 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
 ~~~~~~~~~~~~~~~~
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 74b854b..7f4c77f 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -43,6 +43,8 @@
 
 When in doubt, refer to :pep:`8` for Python code.
 
+`Write comments as complete sentences.`_
+
 Every code file must start with the boilerplate notice of the Apache License.
 Additionally, every Python code file must contain
 
@@ -287,6 +289,7 @@
 
 .. _`GitHub`: https://github.com/pyca/cryptography
 .. _`our mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
+.. _`Write comments as complete sentences.`: http://nedbatchelder.com/blog/201401/comments_should_be_sentences.html
 .. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists
 .. _`pytest`: https://pypi.python.org/pypi/pytest
 .. _`tox`: https://pypi.python.org/pypi/tox
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index 4db3972..ea72af9 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -16,10 +16,58 @@
     * :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
     * :class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`
 
-    It has one additional public attribute.
+    It also exposes the following:
 
     .. attribute:: name
 
         The string name of this backend: ``"openssl"``
 
+    .. method:: activate_osrandom_engine()
+
+        Activates the OS random engine. This will effectively disable OpenSSL's
+        default CSPRNG.
+
+    .. method:: activate_builtin_random()
+
+        This will activate the default OpenSSL CSPRNG.
+
+OS Random Engine
+----------------
+
+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
+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. When
+active this engine will be used to generate all the random data OpenSSL
+requests.
+
+When importing only the binding it is added to the engine list but
+**not activated**.
+
+
+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 same pool as ``/dev/random``.
+
+
 .. _`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)
diff --git a/docs/hazmat/primitives/index.rst b/docs/hazmat/primitives/index.rst
index bde0739..38ed24c 100644
--- a/docs/hazmat/primitives/index.rst
+++ b/docs/hazmat/primitives/index.rst
@@ -11,5 +11,6 @@
     symmetric-encryption
     padding
     key-derivation-functions
+    rsa
     constant-time
     interfaces
diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst
index 4d79ac8..da5a95d 100644
--- a/docs/hazmat/primitives/padding.rst
+++ b/docs/hazmat/primitives/padding.rst
@@ -54,11 +54,11 @@
 
 .. class:: PaddingContext
 
-    When calling ``padder()`` or ``unpadder()`` you will receive an a return
-    object conforming to the ``PaddingContext`` interface. You can then call
-    ``update(data)`` with data until you have fed everything into the context.
-    Once that is done call ``finalize()`` to finish the operation and obtain
-    the remainder of the data.
+    When calling ``padder()`` or ``unpadder()`` the result will conform to the
+    ``PaddingContext`` interface. You can then call ``update(data)`` with data
+    until you have fed everything into the context. Once that is done call
+    ``finalize()`` to finish the operation and obtain the remainder of the
+    data.
 
     .. method:: update(data)
 
diff --git a/docs/hazmat/primitives/rsa.rst b/docs/hazmat/primitives/rsa.rst
new file mode 100644
index 0000000..7c6356c
--- /dev/null
+++ b/docs/hazmat/primitives/rsa.rst
@@ -0,0 +1,58 @@
+.. hazmat::
+
+RSA
+===
+
+.. currentmodule:: cryptography.hazmat.primitives.asymmetric.rsa
+
+`RSA`_ is a `public-key`_ algorithm for encrypting and signing messages.
+
+.. class:: RSAPrivateKey(p, q, private_exponent, public_exponent, modulus)
+    
+    .. versionadded:: 0.2
+
+    An RSA private key is required for decryption and signing of messages.
+
+    Normally you do not need to directly construct private keys because you'll
+    be loading them from a file or generating them automatically.
+
+    .. warning::
+        This method only checks a limited set of properties of its arguments.
+        Using an RSA that you do not trust or with incorrect parameters may
+        lead to insecure operation, crashes, and other undefined behavior. We
+        recommend that you only ever load private keys that were generated with
+        software you trust.
+
+    This class conforms to the
+    :class:`~cryptography.hazmat.primitives.interfaces.RSAPrivateKey`
+    interface.
+
+    :raises TypeError: This is raised when the arguments are not all integers. 
+
+    :raises ValueError: This is raised when the values of `p`, `q`,
+                        `private_exponent`, `public_exponent` or `modulus` do 
+                        not match the bounds specified in `RFC 3447`_.
+
+.. class:: RSAPublicKey(public_exponent, modulus)
+    
+    .. versionadded:: 0.2
+
+    An RSA public key is required for encryption and verification of messages.
+
+    Normally you do not need to directly construct public keys because you'll
+    be loading them from a file, generating them automatically or receiving
+    them from a 3rd party.
+
+    This class conforms to the
+    :class:`~cryptography.hazmat.primitives.interfaces.RSAPublicKey`
+    interface.
+
+    :raises TypeError: This is raised when the arguments are not all integers. 
+
+    :raises ValueError: This is raised when the values of `public_exponent` or
+                        `modulus` do not match the bounds specified in
+                        `RFC 3447`_.
+
+.. _`RSA`: https://en.wikipedia.org/wiki/RSA_(cryptosystem)
+.. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography
+.. _`RFC 3447`: https://tools.ietf.org/html/rfc3447
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 7d95404..85d8e8e 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -388,10 +388,10 @@
 .. class:: CipherContext
 
     When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object
-    you will receive a return object conforming to the ``CipherContext``
-    interface. You can then call ``update(data)`` with data until you have fed
-    everything into the context. Once that is done call ``finalize()`` to
-    finish the operation and obtain the remainder of the data.
+    the result will conform to the ``CipherContext`` interface. You can then
+    call ``update(data)`` with data until you have fed everything into the
+    context. Once that is done call ``finalize()`` to finish the operation and
+    obtain the remainder of the data.
 
     Block ciphers require that plaintext or ciphertext always be a multiple of
     their block size, because of that **padding** is sometimes required to make
@@ -429,14 +429,14 @@
 
     When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object
     with an AEAD mode (e.g.
-    :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM`) you will receive
-    a return object conforming to the ``AEADCipherContext`` and
-    ``CipherContext`` interfaces. If it is an encryption context it will
-    additionally be an ``AEADEncryptionContext`` interface.
-    ``AEADCipherContext`` contains an additional method
-    ``authenticate_additional_data`` for adding additional authenticated but
-    unencrypted data (see note below). You should call this before calls to
-    ``update``. When you are done call ``finalize()`` to finish the operation.
+    :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM`) the result will
+    conform to the ``AEADCipherContext`` and ``CipherContext`` interfaces. If
+    it is an encryption context it will additionally be an
+    ``AEADEncryptionContext`` interface. ``AEADCipherContext`` contains an
+    additional method ``authenticate_additional_data`` for adding additional
+    authenticated but unencrypted data (see note below). You should call this
+    before calls to ``update``. When you are done call ``finalize()`` to finish
+    the operation.
 
     .. note::
 
diff --git a/docs/index.rst b/docs/index.rst
index 49e99be..9114b89 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -59,6 +59,7 @@
     :maxdepth: 2
 
     fernet
+    random-numbers
     exceptions
     glossary
 
diff --git a/docs/random-numbers.rst b/docs/random-numbers.rst
new file mode 100644
index 0000000..cd73a7b
--- /dev/null
+++ b/docs/random-numbers.rst
@@ -0,0 +1,20 @@
+Random number generation
+========================
+
+When generating random data for use in cryptographic operations, such as an
+initialization vector for encryption in
+:class:`~cryptography.hazmat.primitives.ciphers.modes.CBC` mode, you do not
+want to use the standard :mod:`random` module APIs. This is because they do not
+provide a cryptographically secure random number generator, which can result in
+major security issues depending on the algorithms in use.
+
+Therefore, it is our recommendation to always use your operating system's
+provided random number generator, which is available as ``os.urandom()``. For
+example, if you need 16 bytes of random data for an initialization vector, you
+can obtain them with:
+
+.. code-block:: pycon
+
+    >>> import os
+    >>> os.urandom(16)
+    '...'
diff --git a/setup.py b/setup.py
index 57a9575..81a50f4 100644
--- a/setup.py
+++ b/setup.py
@@ -81,7 +81,6 @@
     author_email=about["__email__"],
 
     classifiers=[
-        "Development Status :: 2 - Pre-Alpha",
         "Intended Audience :: Developers",
         "License :: OSI Approved :: Apache Software License",
         "Natural Language :: English",
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index ea04c13..b24808d 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -152,3 +152,72 @@
             pytest.skip("Requires an older OpenSSL")
         with pytest.raises(UnsupportedAlgorithm):
             backend.derive_pbkdf2_hmac(hashes.SHA256(), 10, b"", 1000, b"")
+
+    # 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):
+    def teardown_method(self, method):
+        # we need to reset state to being default. backend is a shared global
+        # for all these tests.
+        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_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)
+        assert name == backend._lib.Cryptography_osrandom_engine_name
+        res = backend._lib.ENGINE_free(e)
+        assert res == 1
+        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_activate_osrandom_no_default(self):
+        backend.activate_builtin_random()
+        e = backend._lib.ENGINE_get_default_RAND()
+        assert e == backend._ffi.NULL
+        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_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.activate_builtin_random()
+        e = backend._lib.ENGINE_get_default_RAND()
+        assert e == backend._ffi.NULL
+
+    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_builtin_random()
+        e = backend._lib.ENGINE_get_default_RAND()
+        assert e == backend._ffi.NULL
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
new file mode 100644
index 0000000..e2aca02
--- /dev/null
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -0,0 +1,173 @@
+# 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.
+
+
+from __future__ import absolute_import, division, print_function
+
+import os
+
+import pytest
+
+from cryptography.hazmat.primitives.asymmetric import rsa
+
+from ...utils import load_pkcs1_vectors, load_vectors_from_file
+
+
+class TestRSA(object):
+    @pytest.mark.parametrize(
+        "pkcs1_example",
+        load_vectors_from_file(
+            os.path.join(
+                "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt"),
+            load_pkcs1_vectors
+        )
+    )
+    def test_load_pss_vect_example_keys(self, pkcs1_example):
+        secret, public = pkcs1_example
+
+        skey = rsa.RSAPrivateKey(**secret)
+        pkey = rsa.RSAPublicKey(**public)
+        pkey2 = skey.public_key()
+
+        assert skey and pkey and pkey2
+
+        assert skey.modulus
+        assert skey.modulus == pkey.modulus
+        assert skey.modulus == skey.n
+        assert skey.public_exponent == pkey.public_exponent
+        assert skey.public_exponent == skey.e
+        assert skey.private_exponent == skey.d
+
+        assert pkey.modulus
+        assert pkey.modulus == pkey2.modulus
+        assert pkey.modulus == pkey.n
+        assert pkey.public_exponent == pkey2.public_exponent
+        assert pkey.public_exponent == pkey.e
+
+        assert skey.key_size
+        assert skey.key_size == pkey.key_size
+        assert skey.key_size == pkey2.key_size
+
+        assert skey.p * skey.q == skey.modulus
+
+    def test_invalid_private_key_argument_types(self):
+        with pytest.raises(TypeError):
+            rsa.RSAPrivateKey(None, None, None, None, None)
+
+    def test_invalid_public_key_argument_types(self):
+        with pytest.raises(TypeError):
+            rsa.RSAPublicKey(None, None)
+
+    def test_invalid_private_key_argument_values(self):
+        # Start with p=3, q=5, private_exponent=14, public_exponent=7,
+        # modulus=15. Then change one value at a time to test the bounds.
+
+        # Test a modulus < 3.
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=3,
+                q=5,
+                private_exponent=14,
+                public_exponent=7,
+                modulus=2
+            )
+
+        # Test a modulus != p * q.
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=3,
+                q=5,
+                private_exponent=14,
+                public_exponent=7,
+                modulus=16
+            )
+
+        # Test a p > modulus.
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=16,
+                q=5,
+                private_exponent=14,
+                public_exponent=7,
+                modulus=15
+            )
+
+        # Test a q > modulus.
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=3,
+                q=16,
+                private_exponent=14,
+                public_exponent=7,
+                modulus=15
+            )
+
+        # Test a private_exponent > modulus
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=3,
+                q=5,
+                private_exponent=16,
+                public_exponent=7,
+                modulus=15
+            )
+
+        # Test a public_exponent < 3
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=3,
+                q=5,
+                private_exponent=14,
+                public_exponent=1,
+                modulus=15
+            )
+
+        # Test a public_exponent > modulus
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=3,
+                q=5,
+                private_exponent=14,
+                public_exponent=17,
+                modulus=15
+            )
+
+        # Test a public_exponent that is not odd.
+        with pytest.raises(ValueError):
+            rsa.RSAPrivateKey(
+                p=3,
+                q=5,
+                private_exponent=14,
+                public_exponent=6,
+                modulus=15
+            )
+
+    def test_invalid_public_key_argument_values(self):
+        # Start with public_exponent=7, modulus=15. Then change one value at a
+        # time to test the bounds.
+
+        # Test a modulus < 3.
+        with pytest.raises(ValueError):
+            rsa.RSAPublicKey(public_exponent=7, modulus=2)
+
+        # Test a public_exponent < 3
+        with pytest.raises(ValueError):
+            rsa.RSAPublicKey(public_exponent=1, modulus=15)
+
+        # Test a public_exponent > modulus
+        with pytest.raises(ValueError):
+            rsa.RSAPublicKey(public_exponent=17, modulus=15)
+
+        # Test a public_exponent that is not odd.
+        with pytest.raises(ValueError):
+            rsa.RSAPublicKey(public_exponent=6, modulus=15)