Merge pull request #300 from dreid/supress-openssl-osx-deprecation-warnings

Supress the deprecation warnings by including an __APPLE__ only preamble.
diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py
index 2e73180..f19c8cc 100644
--- a/cryptography/hazmat/bindings/openssl/backend.py
+++ b/cryptography/hazmat/bindings/openssl/backend.py
@@ -314,12 +314,18 @@
             )
             assert res != 0
             if operation == self._DECRYPT:
-                assert mode.tag is not None
+                if not mode.tag:
+                    raise ValueError("Authentication tag must be supplied "
+                                     "when decrypting")
                 res = self._backend.lib.EVP_CIPHER_CTX_ctrl(
                     ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_TAG,
                     len(mode.tag), mode.tag
                 )
                 assert res != 0
+            else:
+                if mode.tag:
+                    raise ValueError("Authentication tag must be None when "
+                                     "encrypting")
 
         # pass key/iv
         res = self._backend.lib.EVP_CipherInit_ex(ctx, self._backend.ffi.NULL,
diff --git a/cryptography/hazmat/bindings/openssl/bignum.py b/cryptography/hazmat/bindings/openssl/bignum.py
index fcfadff..1b0fe5a 100644
--- a/cryptography/hazmat/bindings/openssl/bignum.py
+++ b/cryptography/hazmat/bindings/openssl/bignum.py
@@ -28,6 +28,9 @@
 
 char *BN_bn2hex(const BIGNUM *);
 int BN_hex2bn(BIGNUM **, const char *);
+int BN_dec2bn(BIGNUM **, const char *);
+
+int BN_num_bits(const BIGNUM *);
 """
 
 MACROS = """
diff --git a/cryptography/hazmat/bindings/openssl/engine.py b/cryptography/hazmat/bindings/openssl/engine.py
index b76befc..1f37766 100644
--- a/cryptography/hazmat/bindings/openssl/engine.py
+++ b/cryptography/hazmat/bindings/openssl/engine.py
@@ -36,6 +36,16 @@
 int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int);
 int ENGINE_set_default(ENGINE *, unsigned int);
 int ENGINE_register_complete(ENGINE *);
+
+int ENGINE_set_default_RSA(ENGINE *);
+int ENGINE_set_default_string(ENGINE *, const char *);
+int ENGINE_set_default_DSA(ENGINE *);
+int ENGINE_set_default_ECDH(ENGINE *);
+int ENGINE_set_default_ECDSA(ENGINE *);
+int ENGINE_set_default_DH(ENGINE *);
+int ENGINE_set_default_RAND(ENGINE *);
+int ENGINE_set_default_ciphers(ENGINE *);
+int ENGINE_set_default_digests(ENGINE *);
 """
 
 MACROS = """
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index 3dac694..f31c240 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -23,11 +23,18 @@
 typedef struct ERR_string_data_st ERR_STRING_DATA;
 
 static const int ERR_LIB_EVP;
+static const int ERR_LIB_PEM;
 
 static const int EVP_F_EVP_ENCRYPTFINAL_EX;
 static const int EVP_F_EVP_DECRYPTFINAL_EX;
 
 static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH;
+
+static const int PEM_F_PEM_READ_BIO_PRIVATEKEY;
+static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO;
+
+static const int PEM_R_BAD_PASSWORD_READ;
+static const int ASN1_R_BAD_PASSWORD_READ;
 """
 
 FUNCTIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/pem.py b/cryptography/hazmat/bindings/openssl/pem.py
index 00f0dc3..cef7839 100644
--- a/cryptography/hazmat/bindings/openssl/pem.py
+++ b/cryptography/hazmat/bindings/openssl/pem.py
@@ -29,6 +29,15 @@
 EVP_PKEY *PEM_read_bio_PrivateKey(BIO *, EVP_PKEY **, pem_password_cb *,
                                   void *);
 
+int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
+                                  char *, int, pem_password_cb *, void *);
+
+int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *,
+                            char *, int, pem_password_cb *, void *);
+
+EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *, EVP_PKEY **, pem_password_cb *,
+                                  void *);
+
 int PEM_write_bio_X509_REQ(BIO *, X509_REQ *);
 
 X509_REQ *PEM_read_bio_X509_REQ(BIO *, X509_REQ **, pem_password_cb *, void *);
diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py
index 21ed5d6..ad0d37b 100644
--- a/cryptography/hazmat/bindings/openssl/rsa.py
+++ b/cryptography/hazmat/bindings/openssl/rsa.py
@@ -16,15 +16,40 @@
 """
 
 TYPES = """
-typedef ... RSA;
+typedef struct rsa_st {
+    BIGNUM *n;
+    BIGNUM *e;
+    BIGNUM *d;
+    BIGNUM *p;
+    BIGNUM *q;
+    BIGNUM *dmp1;
+    BIGNUM *dmq1;
+    BIGNUM *iqmp;
+    ...;
+} RSA;
 typedef ... BN_GENCB;
+static const int RSA_PKCS1_PADDING;
+static const int RSA_SSLV23_PADDING;
+static const int RSA_NO_PADDING;
+static const int RSA_PKCS1_OAEP_PADDING;
+static const int RSA_X931_PADDING;
 """
 
 FUNCTIONS = """
 RSA *RSA_new();
 void RSA_free(RSA *);
+int RSA_size(const RSA *);
 int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *);
 int RSA_check_key(const RSA *);
+RSA *RSAPublicKey_dup(RSA *);
+int RSA_public_encrypt(int, const unsigned char *, unsigned char *,
+                       RSA *, int);
+int RSA_private_encrypt(int, const unsigned char *, unsigned char *,
+                        RSA *, int);
+int RSA_public_decrypt(int, const unsigned char *, unsigned char *,
+                       RSA *, int);
+int RSA_private_decrypt(int, const unsigned char *, unsigned char *,
+                        RSA *, int);
 """
 
 MACROS = """
diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py
index 75a8726..a206b27 100644
--- a/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -17,6 +17,15 @@
 from cryptography.hazmat.primitives import interfaces
 
 
+def _verify_key_size(algorithm, key):
+    # Verify that the key size matches the expected key size
+    if len(key) * 8 not in algorithm.key_sizes:
+        raise ValueError("Invalid key size ({0}) for {1}".format(
+            len(key) * 8, algorithm.name
+        ))
+    return key
+
+
 @utils.register_interface(interfaces.CipherAlgorithm)
 class AES(object):
     name = "AES"
@@ -24,13 +33,7 @@
     key_sizes = frozenset([128, 192, 256])
 
     def __init__(self, key):
-        self.key = key
-
-        # Verify that the key size matches the expected key size
-        if self.key_size not in self.key_sizes:
-            raise ValueError("Invalid key size ({0}) for {1}".format(
-                self.key_size, self.name
-            ))
+        self.key = _verify_key_size(self, key)
 
     @property
     def key_size(self):
@@ -44,13 +47,7 @@
     key_sizes = frozenset([128, 192, 256])
 
     def __init__(self, key):
-        self.key = key
-
-        # Verify that the key size matches the expected key size
-        if self.key_size not in self.key_sizes:
-            raise ValueError("Invalid key size ({0}) for {1}".format(
-                self.key_size, self.name
-            ))
+        self.key = _verify_key_size(self, key)
 
     @property
     def key_size(self):
@@ -68,13 +65,7 @@
             key += key + key
         elif len(key) == 16:
             key += key[:8]
-        self.key = key
-
-        # Verify that the key size matches the expected key size
-        if self.key_size not in self.key_sizes:
-            raise ValueError("Invalid key size ({0}) for {1}".format(
-                self.key_size, self.name
-            ))
+        self.key = _verify_key_size(self, key)
 
     @property
     def key_size(self):
@@ -88,13 +79,7 @@
     key_sizes = frozenset(range(32, 449, 8))
 
     def __init__(self, key):
-        self.key = key
-
-        # Verify that the key size matches the expected key size
-        if self.key_size not in self.key_sizes:
-            raise ValueError("Invalid key size ({0}) for {1}".format(
-                self.key_size, self.name
-            ))
+        self.key = _verify_key_size(self, key)
 
     @property
     def key_size(self):
@@ -105,16 +90,10 @@
 class CAST5(object):
     name = "CAST5"
     block_size = 64
-    key_sizes = frozenset([40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128])
+    key_sizes = frozenset(range(40, 129, 8))
 
     def __init__(self, key):
-        self.key = key
-
-        # Verify that the key size matches the expected key size
-        if self.key_size not in self.key_sizes:
-            raise ValueError("Invalid key size ({0}) for {1}".format(
-                self.key_size, self.name
-            ))
+        self.key = _verify_key_size(self, key)
 
     @property
     def key_size(self):
@@ -128,13 +107,7 @@
     key_sizes = frozenset([40, 56, 64, 80, 128, 192, 256])
 
     def __init__(self, key):
-        self.key = key
-
-        # Verify that the key size matches the expected key size
-        if self.key_size not in self.key_sizes:
-            raise ValueError("Invalid key size ({0}) for {1}".format(
-                self.key_size, self.name
-            ))
+        self.key = _verify_key_size(self, key)
 
     @property
     def key_size(self):
diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py
index 2dbac75..cfa90db 100644
--- a/cryptography/hazmat/primitives/padding.py
+++ b/cryptography/hazmat/primitives/padding.py
@@ -11,12 +11,58 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import cffi
+
 import six
 
 from cryptography import utils
 from cryptography.hazmat.primitives import interfaces
 
 
+_ffi = cffi.FFI()
+_ffi.cdef("""
+bool Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t);
+""")
+_lib = _ffi.verify("""
+#include <stdbool.h>
+
+/* Returns the value of the input with the most-significant-bit copied to all
+   of the bits. */
+static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) {
+    return (1 - (a >> (sizeof(uint8_t) * 8 - 1))) - 1;
+}
+
+/* This returns 0xFF if a < b else 0x00, but does so in a constant time
+   fashion */
+static uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) {
+    a -= b;
+    return Cryptography_DUPLICATE_MSB_TO_ALL(a);
+}
+
+bool Cryptography_check_pkcs7_padding(const uint8_t *data, uint8_t block_len) {
+    uint8_t i;
+    uint8_t pad_size = data[block_len - 1];
+    uint8_t mismatch = 0;
+    for (i = 0; i < block_len; i++) {
+        unsigned int mask = Cryptography_constant_time_lt(i, pad_size);
+        uint8_t b = data[block_len - 1 - i];
+        mismatch |= (mask & (pad_size ^ b));
+    }
+
+    /* Check to make sure the pad_size was within the valid range. */
+    mismatch |= ~Cryptography_constant_time_lt(0, pad_size);
+    mismatch |= Cryptography_constant_time_lt(block_len, pad_size);
+
+    /* Make sure any bits set are copied to the lowest bit */
+    mismatch |= mismatch >> 4;
+    mismatch |= mismatch >> 2;
+    mismatch |= mismatch >> 1;
+    /* Now check the low bit to see if it's set */
+    return (mismatch & 1) == 0;
+}
+""")
+
+
 class PKCS7(object):
     def __init__(self, block_size):
         if not (0 <= block_size < 256):
@@ -102,18 +148,14 @@
         if len(self._buffer) != self.block_size // 8:
             raise ValueError("Invalid padding bytes")
 
+        valid = _lib.Cryptography_check_pkcs7_padding(
+            self._buffer, self.block_size // 8
+        )
+
+        if not valid:
+            raise ValueError("Invalid padding bytes")
+
         pad_size = six.indexbytes(self._buffer, -1)
-
-        if not (0 < pad_size <= self.block_size // 8):
-            raise ValueError("Invalid padding bytes")
-
-        mismatch = 0
-        for b in six.iterbytes(self._buffer[-pad_size:]):
-            mismatch |= b ^ pad_size
-
-        if mismatch != 0:
-            raise ValueError("Invalid padding bytes")
-
         res = self._buffer[:-pad_size]
         self._buffer = None
         return res
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 97f31e0..09833ed 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -47,8 +47,42 @@
 
     from __future__ import absolute_import, division, print_function
 
+API Considerations
+~~~~~~~~~~~~~~~~~~
+
+Most projects' APIs are designed with a philosophy of "make easy things easy,
+and make hard things possible". One of the perils of writing cryptographic code
+is that code that is secure looks just like code that isn't, and produces
+results that are also difficult to distinguish. As a result ``cryptography``
+has, as a design philosophy: "make it hard to do insecure things". Here are a
+few strategies for API design which should be both followed, and should inspire
+other API choices:
+
+If it is incorrect to ignore the result of a method, it should raise an
+exception, and not return a boolean ``True``/``False`` flag. For example, a
+method to verify a signature should raise ``InvalidSignature``, and not return
+whether the signature was valid.
+
+.. code-block:: python
+
+    # This is bad.
+    def verify(sig):
+        # ...
+        return is_valid
+
+    # Good!
+    def verify(sig):
+        # ...
+        if not is_valid:
+            raise InvalidSignature
+
+APIs at the :doc:`/hazmat/primitives/index` layer should always take an
+explicit backend, APIs at the recipes layer should automatically use the
+:func:`~cryptography.hazmat.bindings.default_backend`, but optionally allow
+specifiying a different backend.
+
 C bindings
-----------
+~~~~~~~~~~
 
 When binding C code with ``cffi`` we have our own style guide, it's pretty
 simple.
@@ -141,6 +175,9 @@
 
     .. hazmat::
 
+When referring to a hypothetical individual (such as "a person receiving an
+encrypted message") use gender neutral pronouns (they/them/their).
+
 Development Environment
 -----------------------
 
@@ -158,7 +195,7 @@
 You are now ready to run the tests and build the documentation.
 
 Running Tests
--------------
+~~~~~~~~~~~~~
 
 ``cryptography`` unit tests are found in the ``tests/`` directory and are
 designed to be run using `pytest`_. `pytest`_ will discover the tests
@@ -192,7 +229,7 @@
 will see one or more ``InterpreterNotFound`` errors.
 
 Building Documentation
-----------------------
+~~~~~~~~~~~~~~~~~~~~~~
 
 ``cryptography`` documentation is stored in the ``docs/`` directory. It is
 written in `reStructured Text`_ and rendered using `Sphinx`_.
diff --git a/docs/glossary.rst b/docs/glossary.rst
index b6f2d06..63e0a6c 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -28,3 +28,14 @@
     asymmetric cryptography
         Cryptographic operations where encryption and decryption use different
         keys. There are separate encryption and decryption keys.
+
+    authentication
+        The process of verifying that a message was created by a specific
+        individual (or program). Like encryption, authentication can be either
+        symmetric or asymmetric. Authentication is necessary for effective
+        encryption.
+
+    Ciphertext indistinguishability
+        This is a property of encryption systems whereby two encrypted messages
+        aren't distinguishable without knowing the encryption key. This is
+        considered a basic, necessary property for a working encryption system.
diff --git a/docs/hazmat/bindings/interfaces.rst b/docs/hazmat/bindings/interfaces.rst
index c55d86d..711c82c 100644
--- a/docs/hazmat/bindings/interfaces.rst
+++ b/docs/hazmat/bindings/interfaces.rst
@@ -69,6 +69,8 @@
         :returns:
             :class:`~cryptography.hazmat.primitives.interfaces.CipherContext`
 
+        :raises ValueError: When tag is not None in an AEAD mode
+
 
     .. method:: create_symmetric_decryption_ctx(cipher, mode)
 
@@ -86,6 +88,8 @@
         :returns:
             :class:`~cryptography.hazmat.primitives.interfaces.CipherContext`
 
+        :raises ValueError: When tag is None in an AEAD mode
+
 
 .. class:: HashBackend
 
diff --git a/docs/hazmat/bindings/openssl.rst b/docs/hazmat/bindings/openssl.rst
index 194eeb9..d6bfa67 100644
--- a/docs/hazmat/bindings/openssl.rst
+++ b/docs/hazmat/bindings/openssl.rst
@@ -21,5 +21,5 @@
         and access constants.
 
 
-.. _`CFFI`: http://cffi.readthedocs.org/
+.. _`CFFI`: https://cffi.readthedocs.org/
 .. _`OpenSSL`: https://www.openssl.org/
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 8d8d558..2f39017 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -329,9 +329,10 @@
 
     .. danger::
 
-        When using this mode you MUST not use the decrypted data until every
-        byte has been decrypted. GCM provides NO guarantees of ciphertext
-        integrity until decryption is complete.
+        When using this mode you MUST not use the decrypted data until
+        :meth:`~cryptography.hazmat.primitives.interfaces.CipherContext.finalize`
+        has been called. GCM provides NO guarantees of ciphertext integrity
+        until decryption is complete.
 
     GCM (Galois Counter Mode) is a mode of operation for block ciphers. An
     AEAD (authenticated encryption with additional data) mode is a type of
@@ -349,8 +350,8 @@
                                         Do not reuse an ``initialization_vector``
                                         with a given ``key``.
 
-    :param bytes tag: The tag bytes to verify during decryption. Must be provided
-                      for decryption, but is ignored when encrypting.
+    :param bytes tag: The tag bytes to verify during decryption. When encrypting
+                      this must be None.
 
     .. doctest::
 
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index 2806efd..02de386 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -26,7 +26,9 @@
     Cipher, algorithms, modes
 )
 
-from .utils import generate_aead_exception_test
+from .utils import (
+    generate_aead_exception_test, generate_aead_tag_exception_test
+)
 
 
 @utils.register_interface(interfaces.CipherAlgorithm)
@@ -135,3 +137,11 @@
         ),
         skip_message="Does not support AES GCM",
     )
+    test_aead_tag_exceptions = generate_aead_tag_exception_test(
+        algorithms.AES,
+        modes.GCM,
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.AES("\x00" * 16), modes.GCM("\x00" * 12)
+        ),
+        skip_message="Does not support AES GCM",
+    )
diff --git a/tests/hazmat/primitives/test_utils.py b/tests/hazmat/primitives/test_utils.py
index ebb8b5c..c39364c 100644
--- a/tests/hazmat/primitives/test_utils.py
+++ b/tests/hazmat/primitives/test_utils.py
@@ -3,7 +3,7 @@
 from .utils import (
     base_hash_test, encrypt_test, hash_test, long_string_hash_test,
     base_hmac_test, hmac_test, stream_encryption_test, aead_test,
-    aead_exception_test,
+    aead_exception_test, aead_tag_exception_test,
 )
 
 
@@ -29,7 +29,7 @@
         assert exc_info.value.args[0] == "message!"
 
 
-class TestAEADFinalizeTest(object):
+class TestAEADExceptionTest(object):
     def test_skips_if_only_if_returns_false(self):
         with pytest.raises(pytest.skip.Exception) as exc_info:
             aead_exception_test(
@@ -40,6 +40,17 @@
         assert exc_info.value.args[0] == "message!"
 
 
+class TestAEADTagExceptionTest(object):
+    def test_skips_if_only_if_returns_false(self):
+        with pytest.raises(pytest.skip.Exception) as exc_info:
+            aead_tag_exception_test(
+                None, None, None,
+                only_if=lambda backend: False,
+                skip_message="message!"
+            )
+        assert exc_info.value.args[0] == "message!"
+
+
 class TestHashTest(object):
     def test_skips_if_only_if_returns_false(self):
         with pytest.raises(pytest.skip.Exception) as exc_info:
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index 9aa3a89..705983a 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -353,3 +353,38 @@
     decryptor.update(b"a" * 16)
     with pytest.raises(AttributeError):
         decryptor.tag
+
+
+def generate_aead_tag_exception_test(cipher_factory, mode_factory,
+                                     only_if, skip_message):
+    def test_aead_tag_exception(self):
+        for backend in _ALL_BACKENDS:
+            yield (
+                aead_tag_exception_test,
+                backend,
+                cipher_factory,
+                mode_factory,
+                only_if,
+                skip_message
+            )
+    return test_aead_tag_exception
+
+
+def aead_tag_exception_test(backend, cipher_factory, mode_factory,
+                            only_if, skip_message):
+    if not only_if(backend):
+        pytest.skip(skip_message)
+    cipher = Cipher(
+        cipher_factory(binascii.unhexlify(b"0" * 32)),
+        mode_factory(binascii.unhexlify(b"0" * 24)),
+        backend
+    )
+    with pytest.raises(ValueError):
+        cipher.decryptor()
+    cipher = Cipher(
+        cipher_factory(binascii.unhexlify(b"0" * 32)),
+        mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),
+        backend
+    )
+    with pytest.raises(ValueError):
+        cipher.encryptor()