Merge remote-tracking branch 'origin/master' into pyopenssl-test_crypto-with-optionals
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 912476b..9a57096 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -60,6 +60,13 @@
 
 class HMACBackend(six.with_metaclass(abc.ABCMeta)):
     @abc.abstractmethod
+    def hmac_supported(self, algorithm):
+        """
+        Return True if the hash algorithm is supported for HMAC by this
+        backend.
+        """
+
+    @abc.abstractmethod
     def create_hmac_ctx(self, key, algorithm):
         """
         Create a HashContext for calculating a message authentication code.
diff --git a/cryptography/hazmat/backends/openssl/asn1.py b/cryptography/hazmat/backends/openssl/asn1.py
index 12e8cb3..ec25c22 100644
--- a/cryptography/hazmat/backends/openssl/asn1.py
+++ b/cryptography/hazmat/backends/openssl/asn1.py
@@ -102,7 +102,7 @@
 
 MACROS = """
 ASN1_TIME *M_ASN1_TIME_dup(void *);
-ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM_EXP *);
+ASN1_ITEM_EXP *ASN1_ITEM_ptr(ASN1_ITEM_EXP *);
 
 /* These aren't macros these arguments are all const X on openssl > 1.0.x */
 
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index c82ae5f..6231aad 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -185,6 +185,9 @@
         digest = self.lib.EVP_get_digestbyname(algorithm.name.encode("ascii"))
         return digest != self.ffi.NULL
 
+    def hmac_supported(self, algorithm):
+        return self.hash_supported(algorithm)
+
     def create_hash_ctx(self, algorithm):
         return _HashContext(self, algorithm)
 
diff --git a/cryptography/hazmat/backends/openssl/evp.py b/cryptography/hazmat/backends/openssl/evp.py
index 28b258e..d2297a0 100644
--- a/cryptography/hazmat/backends/openssl/evp.py
+++ b/cryptography/hazmat/backends/openssl/evp.py
@@ -108,12 +108,12 @@
 
 CUSTOMIZATIONS = """
 #ifdef EVP_CTRL_GCM_SET_TAG
-const int Cryptography_HAS_GCM = 1;
+const long Cryptography_HAS_GCM = 1;
 #else
-const int Cryptography_HAS_GCM = 0;
-const int EVP_CTRL_GCM_GET_TAG = -1;
-const int EVP_CTRL_GCM_SET_TAG = -1;
-const int EVP_CTRL_GCM_SET_IVLEN = -1;
+const long Cryptography_HAS_GCM = 0;
+const long EVP_CTRL_GCM_GET_TAG = -1;
+const long EVP_CTRL_GCM_SET_TAG = -1;
+const long EVP_CTRL_GCM_SET_IVLEN = -1;
 #endif
 """
 
diff --git a/cryptography/hazmat/backends/openssl/ssl.py b/cryptography/hazmat/backends/openssl/ssl.py
index 3fd0bf2..f99c263 100644
--- a/cryptography/hazmat/backends/openssl/ssl.py
+++ b/cryptography/hazmat/backends/openssl/ssl.py
@@ -54,7 +54,6 @@
 static const int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
 static const int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG;
 static const int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER;
-static const int SSL_OP_MSIE_SSLV2_RSA_PADDING;
 static const int SSL_OP_SSLEAY_080_CLIENT_DH_BUG;
 static const int SSL_OP_TLS_D5_BUG;
 static const int SSL_OP_TLS_BLOCK_PADDING_BUG;
@@ -144,8 +143,8 @@
 void SSL_set_verify_depth(SSL *, int);
 int SSL_get_verify_depth(const SSL *);
 int (*SSL_get_verify_callback(const SSL *))(int, X509_STORE_CTX *);
-void SSL_set_info_callback(SSL *, void (*)());
-void (*SSL_get_info_callback(const SSL *))();
+void SSL_set_info_callback(SSL *ssl, void (*)(const SSL *, int, int));
+void (*SSL_get_info_callback(const SSL *))(const SSL *, int, int);
 SSL *SSL_new(SSL_CTX *);
 void SSL_free(SSL *);
 int SSL_set_fd(SSL *, int);
@@ -207,7 +206,7 @@
 int SSL_want_read(const SSL *);
 int SSL_want_write(const SSL *);
 
-int SSL_total_renegotiations(const SSL *);
+int SSL_total_renegotiations(SSL *);
 
 long SSL_CTX_set_options(SSL_CTX *, long);
 long SSL_CTX_get_options(SSL_CTX *);
@@ -255,18 +254,18 @@
 
 CUSTOMIZATIONS = """
 #ifdef OPENSSL_NO_SSL2
-static const int Cryptography_HAS_SSL2 = 0;
+static const long Cryptography_HAS_SSL2 = 0;
 SSL_METHOD* (*SSLv2_method)() = NULL;
 SSL_METHOD* (*SSLv2_client_method)() = NULL;
 SSL_METHOD* (*SSLv2_server_method)() = NULL;
 #else
-static const int Cryptography_HAS_SSL2 = 1;
+static const long Cryptography_HAS_SSL2 = 1;
 #endif
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-static const int Cryptography_HAS_TLSEXT_HOSTNAME = 1;
+static const long Cryptography_HAS_TLSEXT_HOSTNAME = 1;
 #else
-static const int Cryptography_HAS_TLSEXT_HOSTNAME = 0;
+static const long Cryptography_HAS_TLSEXT_HOSTNAME = 0;
 void (*SSL_set_tlsext_host_name)(SSL *, char *) = NULL;
 const char* (*SSL_get_servername)(const SSL *, const int) = NULL;
 void (*SSL_CTX_set_tlsext_servername_callback)(
@@ -275,17 +274,17 @@
 #endif
 
 #ifdef SSL_MODE_RELEASE_BUFFERS
-static const int Cryptography_HAS_RELEASE_BUFFERS = 1;
+static const long Cryptography_HAS_RELEASE_BUFFERS = 1;
 #else
-static const int Cryptography_HAS_RELEASE_BUFFERS = 0;
-const int SSL_MODE_RELEASE_BUFFERS = 0;
+static const long Cryptography_HAS_RELEASE_BUFFERS = 0;
+const long SSL_MODE_RELEASE_BUFFERS = 0;
 #endif
 
 #ifdef SSL_OP_NO_COMPRESSION
-static const int Cryptography_HAS_OP_NO_COMPRESSION = 1;
+static const long Cryptography_HAS_OP_NO_COMPRESSION = 1;
 #else
-static const int Cryptography_HAS_OP_NO_COMPRESSION = 0;
-const int SSL_OP_NO_COMPRESSION = 0;
+static const long Cryptography_HAS_OP_NO_COMPRESSION = 0;
+const long SSL_OP_NO_COMPRESSION = 0;
 #endif
 """
 
diff --git a/cryptography/hazmat/backends/openssl/x509.py b/cryptography/hazmat/backends/openssl/x509.py
index dd7815f..5cba476 100644
--- a/cryptography/hazmat/backends/openssl/x509.py
+++ b/cryptography/hazmat/backends/openssl/x509.py
@@ -47,7 +47,7 @@
 } X509_REVOKED;
 
 typedef struct {
-    struct x509_revoked_st *revoked;
+    struct stack_st_X509_REVOKED *revoked;
     ...;
 } X509_CRL_INFO;
 
@@ -178,8 +178,8 @@
 void sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int);
 void sk_X509_EXTENSION_free(X509_EXTENSIONS *);
 
-int sk_X509_REVOKED_num(struct x509_revoked_st *);
-X509_REVOKED *sk_X509_REVOKED_value(struct x509_revoked_st *, int);
+int sk_X509_REVOKED_num(struct stack_st_X509_REVOKED *);
+X509_REVOKED *sk_X509_REVOKED_value(struct stack_st_X509_REVOKED *, int);
 
 /* These aren't macros these arguments are all const X on openssl > 1.0.x */
 int X509_CRL_set_lastUpdate(X509_CRL *, const ASN1_TIME *);
diff --git a/docs/api-stability.rst b/docs/api-stability.rst
new file mode 100644
index 0000000..e87cc14
--- /dev/null
+++ b/docs/api-stability.rst
@@ -0,0 +1,51 @@
+API Stability
+=============
+
+From its first release, ``cryptography`` will have a strong API stability
+policy.
+
+What does this policy cover?
+----------------------------
+
+This policy includes any API or behavior which is documented in this
+documentation.
+
+What does "stable" mean?
+------------------------
+
+* Public APIs will not be removed or renamed without providing a compatibility
+  alias.
+* The behavior of existing APIs will not change.
+
+What doesn't this policy cover?
+-------------------------------
+
+* We may add new features, things like the result of ``dir(obj))`` or the
+  contents of ``obj.__dict__`` may change.
+* Objects are not guaranteed to be pickleable, and pickled objects from one
+  version of ``cryptography`` may not be loadable in future versions.
+* Development versions of ``cryptography``. Before a feature is in a release,
+  it is not covered by this policy and may change.
+
+Security
+~~~~~~~~
+
+One exception to our API stability policy is for security. We will violate this
+policy as necessary in order to resolve a security issue or harden
+``cryptography`` against a possible attack.
+
+Deprecation
+-----------
+
+From time to time we will want to change the behavior of an API or remove it
+entirely. In that case, here's how the process will work:
+
+* In ``cryptography X.Y`` the feature exists.
+* In ``cryptography X.Y+1`` using that feature will emit a
+  ``PendingDeprecationWarning``.
+* In ``cryptography X.Y+2`` using that feature will emit a
+  ``DeprecationWarning``.
+* In ``cryptography X.Y+3`` the feature will be removed or changed.
+
+In short, code which runs without warnings will always continue to work for a
+period of two releases.
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 744f209..620e1b6 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -136,7 +136,6 @@
     // Bad
     long f(int,char *)
 
-
 Documentation
 -------------
 
diff --git a/docs/hazmat/backends/index.rst b/docs/hazmat/backends/index.rst
index a89cf0d..0695128 100644
--- a/docs/hazmat/backends/index.rst
+++ b/docs/hazmat/backends/index.rst
@@ -1,17 +1,10 @@
 .. hazmat::
 
-Bindings
+Backends
 ========
 
-.. toctree::
-    :maxdepth: 1
-
-    openssl
-    interfaces
-
-
-Getting a Backend Provider
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+Getting a Backend
+-----------------
 
 .. currentmodule:: cryptography.hazmat.backends
 
@@ -19,8 +12,7 @@
 the widest number of supported cryptographic algorithms as well as supporting
 platform specific implementations.
 
-You can get the default backend by calling
-:func:`~default_backend`.
+You can get the default backend by calling :func:`~default_backend`.
 
 The default backend will change over time as we implement new backends and
 the libraries we use in those backends changes.
@@ -32,3 +24,11 @@
         :class:`~interfaces.CipherBackend`, :class:`~interfaces.HashBackend`, and
         :class:`~interfaces.HMACBackend`.
 
+Individual Backends
+-------------------
+
+.. toctree::
+    :maxdepth: 1
+
+    openssl
+    interfaces
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index b524943..5b6cd64 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -126,6 +126,17 @@
     A backend with methods for using cryptographic hash functions as message
     authentication codes.
 
+    .. method:: hmac_supported(algorithm)
+
+        Check if the specified ``algorithm`` is supported by this backend.
+
+        :param algorithm: An instance of a
+            :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+            provider.
+
+        :returns: ``True`` if the specified ``algorithm`` is supported for HMAC
+            by this backend, otherwise ``False``.
+
     .. method:: create_hmac_ctx(algorithm)
 
         Create a
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index 12fbff0..5e51c75 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -1,7 +1,7 @@
 .. hazmat::
 
-OpenSSL
-=======
+OpenSSL Backend
+===============
 
 These are `CFFI`_ bindings to the `OpenSSL`_ C library.
 
diff --git a/docs/index.rst b/docs/index.rst
index 381063d..70558bd 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -75,4 +75,5 @@
 
     contributing
     security
+    api-stability
     community
diff --git a/pytest.ini b/pytest.ini
index 723735a..1aeb23f 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,2 +1,6 @@
 [pytest]
 addopts = -r s
+markers =
+    hmac: this test requires a backend providing HMACBackend
+    cipher: this test requires a backend providing CipherBackend
+    hash: this test requires a backend providing HashBackend
diff --git a/tests/conftest.py b/tests/conftest.py
index 7166280..e059b63 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,5 +1,21 @@
+import pytest
+
+from cryptography.hazmat.backends.interfaces import (
+    HMACBackend, CipherBackend, HashBackend
+)
+
+from .utils import check_for_iface
+
+
 def pytest_generate_tests(metafunc):
     from cryptography.hazmat.backends import _ALL_BACKENDS
 
     if "backend" in metafunc.fixturenames:
         metafunc.parametrize("backend", _ALL_BACKENDS)
+
+
+@pytest.mark.trylast
+def pytest_runtest_setup(item):
+    check_for_iface("hmac", HMACBackend, item)
+    check_for_iface("cipher", CipherBackend, item)
+    check_for_iface("hash", HashBackend, item)
diff --git a/tests/hazmat/primitives/test_3des.py b/tests/hazmat/primitives/test_3des.py
index 0db56f4..439ca25 100644
--- a/tests/hazmat/primitives/test_3des.py
+++ b/tests/hazmat/primitives/test_3des.py
@@ -20,12 +20,15 @@
 import binascii
 import os
 
+import pytest
+
 from cryptography.hazmat.primitives.ciphers import algorithms, modes
 
 from .utils import generate_encrypt_test
 from ...utils import load_nist_vectors
 
 
+@pytest.mark.cipher
 class TestTripleDES_CBC(object):
     test_KAT = generate_encrypt_test(
         load_nist_vectors,
@@ -39,6 +42,10 @@
         ],
         lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
         lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.TripleDES("\x00" * 8), modes.CBC("\x00" * 8)
+        ),
+        skip_message="Does not support TripleDES CBC",
     )
 
     test_MMT = generate_encrypt_test(
@@ -53,9 +60,14 @@
             binascii.unhexlify(key1 + key2 + key3)
         ),
         lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.TripleDES("\x00" * 8), modes.CBC("\x00" * 8)
+        ),
+        skip_message="Does not support TripleDES CBC",
     )
 
 
+@pytest.mark.cipher
 class TestTripleDES_OFB(object):
     test_KAT = generate_encrypt_test(
         load_nist_vectors,
@@ -69,6 +81,10 @@
         ],
         lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
         lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.TripleDES("\x00" * 8), modes.OFB("\x00" * 8)
+        ),
+        skip_message="Does not support TripleDES OFB",
     )
 
     test_MMT = generate_encrypt_test(
@@ -83,9 +99,14 @@
             binascii.unhexlify(key1 + key2 + key3)
         ),
         lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.TripleDES("\x00" * 8), modes.OFB("\x00" * 8)
+        ),
+        skip_message="Does not support TripleDES OFB",
     )
 
 
+@pytest.mark.cipher
 class TestTripleDES_CFB(object):
     test_KAT = generate_encrypt_test(
         load_nist_vectors,
@@ -99,6 +120,10 @@
         ],
         lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
         lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.TripleDES("\x00" * 8), modes.CFB("\x00" * 8)
+        ),
+        skip_message="Does not support TripleDES CFB",
     )
 
     test_MMT = generate_encrypt_test(
@@ -113,4 +138,8 @@
             binascii.unhexlify(key1 + key2 + key3)
         ),
         lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.TripleDES("\x00" * 8), modes.CFB("\x00" * 8)
+        ),
+        skip_message="Does not support TripleDES CFB",
     )
diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py
index 9e5a3cb..e9ef385 100644
--- a/tests/hazmat/primitives/test_aes.py
+++ b/tests/hazmat/primitives/test_aes.py
@@ -16,6 +16,8 @@
 import binascii
 import os
 
+import pytest
+
 from cryptography.hazmat.primitives.ciphers import algorithms, modes
 
 from .utils import generate_encrypt_test, generate_aead_test
@@ -24,6 +26,7 @@
 )
 
 
+@pytest.mark.cipher
 class TestAES(object):
     test_CBC = generate_encrypt_test(
         load_nist_vectors,
@@ -47,6 +50,10 @@
         ],
         lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
         lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.AES("\x00" * 16), modes.CBC("\x00" * 16)
+        ),
+        skip_message="Does not support AES CBC",
     )
 
     test_ECB = generate_encrypt_test(
@@ -71,6 +78,10 @@
         ],
         lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
         lambda **kwargs: modes.ECB(),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.AES("\x00" * 16), modes.ECB()
+        ),
+        skip_message="Does not support AES ECB",
     )
 
     test_OFB = generate_encrypt_test(
@@ -95,6 +106,10 @@
         ],
         lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
         lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.AES("\x00" * 16), modes.OFB("\x00" * 16)
+        ),
+        skip_message="Does not support AES OFB",
     )
 
     test_CFB = generate_encrypt_test(
@@ -119,6 +134,10 @@
         ],
         lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
         lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
+        only_if=lambda backend: backend.cipher_supported(
+            algorithms.AES("\x00" * 16), modes.CFB("\x00" * 16)
+        ),
+        skip_message="Does not support AES CFB",
     )
 
     test_CTR = generate_encrypt_test(
diff --git a/tests/hazmat/primitives/test_arc4.py b/tests/hazmat/primitives/test_arc4.py
index a9ef2bb..f2e2452 100644
--- a/tests/hazmat/primitives/test_arc4.py
+++ b/tests/hazmat/primitives/test_arc4.py
@@ -16,12 +16,15 @@
 import binascii
 import os
 
+import pytest
+
 from cryptography.hazmat.primitives.ciphers import algorithms
 
 from .utils import generate_stream_encryption_test
 from ...utils import load_nist_vectors
 
 
+@pytest.mark.cipher
 class TestARC4(object):
     test_rfc = generate_stream_encryption_test(
         load_nist_vectors,
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index 573f563..22a7c02 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -41,6 +41,7 @@
     name = "dummy-cipher"
 
 
+@pytest.mark.cipher
 class TestCipher(object):
     def test_creates_encryptor(self, backend):
         cipher = Cipher(
@@ -64,6 +65,7 @@
             Cipher(algorithm, mode=None, backend=backend)
 
 
+@pytest.mark.cipher
 class TestCipherContext(object):
     def test_use_after_finalize(self, backend):
         cipher = Cipher(
@@ -134,6 +136,7 @@
             decryptor.finalize()
 
 
+@pytest.mark.cipher
 class TestAEADCipherContext(object):
     test_aead_exceptions = generate_aead_exception_test(
         algorithms.AES,
diff --git a/tests/hazmat/primitives/test_blowfish.py b/tests/hazmat/primitives/test_blowfish.py
index 065855d..79ceabe 100644
--- a/tests/hazmat/primitives/test_blowfish.py
+++ b/tests/hazmat/primitives/test_blowfish.py
@@ -16,12 +16,15 @@
 import binascii
 import os
 
+import pytest
+
 from cryptography.hazmat.primitives.ciphers import algorithms, modes
 
 from .utils import generate_encrypt_test
 from ...utils import load_nist_vectors
 
 
+@pytest.mark.cipher
 class TestBlowfish(object):
     test_ECB = generate_encrypt_test(
         load_nist_vectors,
diff --git a/tests/hazmat/primitives/test_camellia.py b/tests/hazmat/primitives/test_camellia.py
index 6e5fe68..c376220 100644
--- a/tests/hazmat/primitives/test_camellia.py
+++ b/tests/hazmat/primitives/test_camellia.py
@@ -16,6 +16,8 @@
 import binascii
 import os
 
+import pytest
+
 from cryptography.hazmat.primitives.ciphers import algorithms, modes
 
 from .utils import generate_encrypt_test
@@ -24,6 +26,7 @@
 )
 
 
+@pytest.mark.cipher
 class TestCamellia(object):
     test_ECB = generate_encrypt_test(
         load_cryptrec_vectors,
diff --git a/tests/hazmat/primitives/test_cast5.py b/tests/hazmat/primitives/test_cast5.py
index 406f9b5..a4789c6 100644
--- a/tests/hazmat/primitives/test_cast5.py
+++ b/tests/hazmat/primitives/test_cast5.py
@@ -16,12 +16,15 @@
 import binascii
 import os
 
+import pytest
+
 from cryptography.hazmat.primitives.ciphers import algorithms, modes
 
 from .utils import generate_encrypt_test
 from ...utils import load_nist_vectors
 
 
+@pytest.mark.cipher
 class TestCAST5(object):
     test_ECB = generate_encrypt_test(
         load_nist_vectors,
diff --git a/tests/hazmat/primitives/test_hash_vectors.py b/tests/hazmat/primitives/test_hash_vectors.py
index a865581..d9febea 100644
--- a/tests/hazmat/primitives/test_hash_vectors.py
+++ b/tests/hazmat/primitives/test_hash_vectors.py
@@ -15,12 +15,15 @@
 
 import os
 
+import pytest
+
 from cryptography.hazmat.primitives import hashes
 
 from .utils import generate_hash_test, generate_long_string_hash_test
 from ...utils import load_hash_vectors
 
 
+@pytest.mark.hash
 class TestSHA1(object):
     test_SHA1 = generate_hash_test(
         load_hash_vectors,
@@ -35,6 +38,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA224(object):
     test_SHA224 = generate_hash_test(
         load_hash_vectors,
@@ -49,6 +53,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA256(object):
     test_SHA256 = generate_hash_test(
         load_hash_vectors,
@@ -63,6 +68,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA384(object):
     test_SHA384 = generate_hash_test(
         load_hash_vectors,
@@ -77,6 +83,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA512(object):
     test_SHA512 = generate_hash_test(
         load_hash_vectors,
@@ -91,6 +98,7 @@
     )
 
 
+@pytest.mark.hash
 class TestRIPEMD160(object):
     test_RIPEMD160 = generate_hash_test(
         load_hash_vectors,
@@ -111,6 +119,7 @@
     )
 
 
+@pytest.mark.hash
 class TestWhirlpool(object):
     test_whirlpool = generate_hash_test(
         load_hash_vectors,
@@ -133,6 +142,7 @@
     )
 
 
+@pytest.mark.hash
 class TestMD5(object):
     test_md5 = generate_hash_test(
         load_hash_vectors,
diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py
index 72bc3e2..45faaab 100644
--- a/tests/hazmat/primitives/test_hashes.py
+++ b/tests/hazmat/primitives/test_hashes.py
@@ -31,6 +31,7 @@
     name = "unsupported-dummy-hash"
 
 
+@pytest.mark.hash
 class TestHashContext(object):
     def test_hash_reject_unicode(self, backend):
         m = hashes.Hash(hashes.SHA1(), backend=backend)
@@ -68,6 +69,7 @@
             hashes.Hash(UnsupportedDummyHash(), backend)
 
 
+@pytest.mark.hash
 class TestSHA1(object):
     test_SHA1 = generate_base_hash_test(
         hashes.SHA1(),
@@ -78,6 +80,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA224(object):
     test_SHA224 = generate_base_hash_test(
         hashes.SHA224(),
@@ -88,6 +91,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA256(object):
     test_SHA256 = generate_base_hash_test(
         hashes.SHA256(),
@@ -98,6 +102,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA384(object):
     test_SHA384 = generate_base_hash_test(
         hashes.SHA384(),
@@ -108,6 +113,7 @@
     )
 
 
+@pytest.mark.hash
 class TestSHA512(object):
     test_SHA512 = generate_base_hash_test(
         hashes.SHA512(),
@@ -118,6 +124,7 @@
     )
 
 
+@pytest.mark.hash
 class TestRIPEMD160(object):
     test_RIPEMD160 = generate_base_hash_test(
         hashes.RIPEMD160(),
@@ -128,6 +135,7 @@
     )
 
 
+@pytest.mark.hash
 class TestWhirlpool(object):
     test_Whirlpool = generate_base_hash_test(
         hashes.Whirlpool(),
@@ -138,6 +146,7 @@
     )
 
 
+@pytest.mark.hash
 class TestMD5(object):
     test_MD5 = generate_base_hash_test(
         hashes.MD5(),
diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py
index 124c437..6d8cc27 100644
--- a/tests/hazmat/primitives/test_hmac.py
+++ b/tests/hazmat/primitives/test_hmac.py
@@ -31,10 +31,11 @@
         name = "unsupported-dummy-hash"
 
 
+@pytest.mark.hmac
 class TestHMAC(object):
     test_copy = generate_base_hmac_test(
         hashes.MD5(),
-        only_if=lambda backend: backend.hash_supported(hashes.MD5),
+        only_if=lambda backend: backend.hmac_supported(hashes.MD5),
         skip_message="Does not support MD5",
     )
 
diff --git a/tests/hazmat/primitives/test_hmac_vectors.py b/tests/hazmat/primitives/test_hmac_vectors.py
index 7d0f156..9bc06a2 100644
--- a/tests/hazmat/primitives/test_hmac_vectors.py
+++ b/tests/hazmat/primitives/test_hmac_vectors.py
@@ -13,12 +13,15 @@
 
 from __future__ import absolute_import, division, print_function
 
+import pytest
+
 from cryptography.hazmat.primitives import hashes
 
 from .utils import generate_hmac_test
 from ...utils import load_hash_vectors
 
 
+@pytest.mark.hmac
 class TestHMAC_MD5(object):
     test_hmac_md5 = generate_hmac_test(
         load_hash_vectors,
@@ -27,11 +30,12 @@
             "rfc-2202-md5.txt",
         ],
         hashes.MD5(),
-        only_if=lambda backend: backend.hash_supported(hashes.MD5),
+        only_if=lambda backend: backend.hmac_supported(hashes.MD5),
         skip_message="Does not support MD5",
     )
 
 
+@pytest.mark.hmac
 class TestHMAC_SHA1(object):
     test_hmac_sha1 = generate_hmac_test(
         load_hash_vectors,
@@ -40,11 +44,12 @@
             "rfc-2202-sha1.txt",
         ],
         hashes.SHA1(),
-        only_if=lambda backend: backend.hash_supported(hashes.SHA1),
+        only_if=lambda backend: backend.hmac_supported(hashes.SHA1),
         skip_message="Does not support SHA1",
     )
 
 
+@pytest.mark.hmac
 class TestHMAC_SHA224(object):
     test_hmac_sha224 = generate_hmac_test(
         load_hash_vectors,
@@ -53,11 +58,12 @@
             "rfc-4231-sha224.txt",
         ],
         hashes.SHA224(),
-        only_if=lambda backend: backend.hash_supported(hashes.SHA224),
+        only_if=lambda backend: backend.hmac_supported(hashes.SHA224),
         skip_message="Does not support SHA224",
     )
 
 
+@pytest.mark.hmac
 class TestHMAC_SHA256(object):
     test_hmac_sha256 = generate_hmac_test(
         load_hash_vectors,
@@ -66,11 +72,12 @@
             "rfc-4231-sha256.txt",
         ],
         hashes.SHA256(),
-        only_if=lambda backend: backend.hash_supported(hashes.SHA256),
+        only_if=lambda backend: backend.hmac_supported(hashes.SHA256),
         skip_message="Does not support SHA256",
     )
 
 
+@pytest.mark.hmac
 class TestHMAC_SHA384(object):
     test_hmac_sha384 = generate_hmac_test(
         load_hash_vectors,
@@ -79,11 +86,12 @@
             "rfc-4231-sha384.txt",
         ],
         hashes.SHA384(),
-        only_if=lambda backend: backend.hash_supported(hashes.SHA384),
+        only_if=lambda backend: backend.hmac_supported(hashes.SHA384),
         skip_message="Does not support SHA384",
     )
 
 
+@pytest.mark.hmac
 class TestHMAC_SHA512(object):
     test_hmac_sha512 = generate_hmac_test(
         load_hash_vectors,
@@ -92,11 +100,12 @@
             "rfc-4231-sha512.txt",
         ],
         hashes.SHA512(),
-        only_if=lambda backend: backend.hash_supported(hashes.SHA512),
+        only_if=lambda backend: backend.hmac_supported(hashes.SHA512),
         skip_message="Does not support SHA512",
     )
 
 
+@pytest.mark.hmac
 class TestHMAC_RIPEMD160(object):
     test_hmac_ripemd160 = generate_hmac_test(
         load_hash_vectors,
@@ -105,6 +114,6 @@
             "rfc-2286-ripemd160.txt",
         ],
         hashes.RIPEMD160(),
-        only_if=lambda backend: backend.hash_supported(hashes.RIPEMD160),
+        only_if=lambda backend: backend.hmac_supported(hashes.RIPEMD160),
         skip_message="Does not support RIPEMD160",
     )
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index b00d318..e018477 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -22,8 +22,7 @@
 
 
 def generate_encrypt_test(param_loader, path, file_names, cipher_factory,
-                          mode_factory, only_if=lambda backend: True,
-                          skip_message=None):
+                          mode_factory, only_if, skip_message=None):
     all_params = _load_all_params(path, file_names, param_loader)
 
     @pytest.mark.parametrize("params", all_params)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 5c58fd7..a65091f 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -14,14 +14,33 @@
 import os
 import textwrap
 
+import pretend
+
 import pytest
 
 from .utils import (
     load_nist_vectors, load_vectors_from_file, load_cryptrec_vectors,
-    load_openssl_vectors, load_hash_vectors,
+    load_openssl_vectors, load_hash_vectors, check_for_iface
 )
 
 
+class FakeInterface(object):
+    pass
+
+
+def test_check_for_iface():
+    item = pretend.stub(keywords=["fake_name"], funcargs={"backend": True})
+    with pytest.raises(pytest.skip.Exception) as exc_info:
+        check_for_iface("fake_name", FakeInterface, item)
+    assert exc_info.value.args[0] == "True backend does not support fake_name"
+
+    item = pretend.stub(
+        keywords=["fake_name"],
+        funcargs={"backend": FakeInterface()}
+    )
+    check_for_iface("fake_name", FakeInterface, item)
+
+
 def test_load_nist_vectors():
     vector_data = textwrap.dedent("""
     # CAVS 11.1
diff --git a/tests/utils.py b/tests/utils.py
index 94f97d5..82021a5 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -11,7 +11,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import os.path
+import os
+
+import pytest
+
+
+def check_for_iface(name, iface, item):
+    if name in item.keywords and "backend" in item.funcargs:
+        if not isinstance(item.funcargs["backend"], iface):
+            pytest.skip("{0} backend does not support {1}".format(
+                item.funcargs["backend"], name
+            ))
 
 
 def load_vectors_from_file(filename, loader):
diff --git a/tox.ini b/tox.ini
index 39fe024..6114311 100644
--- a/tox.ini
+++ b/tox.ini
@@ -7,7 +7,7 @@
     coverage
     pretend
 commands =
-    coverage run --source=cryptography/,tests/ -m pytest --strict
+    coverage run --source=cryptography/,tests/ -m pytest --capture=no --strict
     coverage report -m
 
 [testenv:docs]
@@ -24,7 +24,7 @@
 # Temporarily disable coverage on pypy because of performance problems with
 # coverage.py on pypy.
 [testenv:pypy]
-commands = py.test
+commands = py.test --capture=no
 
 [testenv:pep8]
 deps = flake8