diff --git a/.travis.yml b/.travis.yml
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_LnRyYXZpcy55bWw=..7fde27822704d762e0422d02c10af49328e74159_LnRyYXZpcy55bWw= 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -64,6 +64,9 @@
         - python: 3.6
           services: docker
           env: TOXENV=py36 DOCKER=pyca/cryptography-runner-centos8
+        - python: 3.6
+          services: docker
+          env: TOXENV=py36 OPENSSL_FORCE_FIPS_MODE=1 DOCKER=pyca/cryptography-runner-centos8-fips
         - python: 2.7
           services: docker
           env: TOXENV=py27 DOCKER=pyca/cryptography-runner-stretch
diff --git a/.travis/run.sh b/.travis/run.sh
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_LnRyYXZpcy9ydW4uc2g=..7fde27822704d762e0422d02c10af49328e74159_LnRyYXZpcy9ydW4uc2g= 100755
--- a/.travis/run.sh
+++ b/.travis/run.sh
@@ -32,6 +32,7 @@
         -v "${TRAVIS_BUILD_DIR}":"${TRAVIS_BUILD_DIR}" \
         -v "${HOME}/wycheproof":/wycheproof \
         -w "${TRAVIS_BUILD_DIR}" \
+        -e OPENSSL_FORCE_FIPS_MODE \
         -e TOXENV "${DOCKER}" \
         /bin/sh -c "tox -- --wycheproof-root='/wycheproof'"
 elif [ -n "${TOXENV}" ]; then
diff --git a/.travis/upload_coverage.sh b/.travis/upload_coverage.sh
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_LnRyYXZpcy91cGxvYWRfY292ZXJhZ2Uuc2g=..7fde27822704d762e0422d02c10af49328e74159_LnRyYXZpcy91cGxvYWRfY292ZXJhZ2Uuc2g= 100755
--- a/.travis/upload_coverage.sh
+++ b/.travis/upload_coverage.sh
@@ -14,8 +14,8 @@
             source ~/.venv/bin/activate
             curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash
 
-            bash codecov.sh -Z -e TRAVIS_OS_NAME,TOXENV,OPENSSL,DOCKER || \
-                bash codecov.sh -Z -e TRAVIS_OS_NAME,TOXENV,OPENSSL,DOCKER
+            bash codecov.sh -Z -e TRAVIS_OS_NAME,TOXENV,OPENSSL,DOCKER,OPENSSL_FORCE_FIPS_MODE || \
+                bash codecov.sh -Z -e TRAVIS_OS_NAME,TOXENV,OPENSSL,DOCKER,OPENSSL_FORCE_FIPS_MODE
             ;;
     esac
 fi
diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_c3JjL19jZmZpX3NyYy9vcGVuc3NsL2Vyci5weQ==..7fde27822704d762e0422d02c10af49328e74159_c3JjL19jZmZpX3NyYy9vcGVuc3NsL2Vyci5weQ== 100644
--- a/src/_cffi_src/openssl/err.py
+++ b/src/_cffi_src/openssl/err.py
@@ -81,6 +81,7 @@
 static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED;
 
 static const int EC_R_UNKNOWN_GROUP;
+static const int EC_R_NOT_A_NIST_PRIME;
 
 static const int PEM_R_BAD_BASE64_DECODE;
 static const int PEM_R_BAD_DECRYPT;
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_c3JjL2NyeXB0b2dyYXBoeS9oYXptYXQvYmFja2VuZHMvb3BlbnNzbC9iYWNrZW5kLnB5..7fde27822704d762e0422d02c10af49328e74159_c3JjL2NyeXB0b2dyYXBoeS9oYXptYXQvYmFja2VuZHMvb3BlbnNzbC9iYWNrZW5kLnB5 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -7,6 +7,7 @@
 import collections
 import contextlib
 import itertools
+import warnings
 from contextlib import contextmanager
 
 import six
@@ -119,7 +120,30 @@
     """
     name = "openssl"
 
+    # FIPS has opinions about acceptable algorithms and key sizes, but the
+    # disallowed algorithms are still present in OpenSSL. They just error if
+    # you try to use them. To avoid that we allowlist the algorithms in
+    # FIPS 140-3. This isn't ideal, but FIPS 140-3 is trash so here we are.
+    _fips_aead = {
+        b'aes-128-ccm', b'aes-192-ccm', b'aes-256-ccm',
+        b'aes-128-gcm', b'aes-192-gcm', b'aes-256-gcm',
+    }
+    _fips_ciphers = (
+        AES, TripleDES
+    )
+    _fips_hashes = (
+        hashes.SHA1, hashes.SHA224, hashes.SHA256, hashes.SHA384,
+        hashes.SHA512, hashes.SHA512_224, hashes.SHA512_256, hashes.SHA3_224,
+        hashes.SHA3_256, hashes.SHA3_384, hashes.SHA3_512, hashes.SHAKE128,
+        hashes.SHAKE256,
+    )
+    _fips_rsa_min_key_size = 2048
+    _fips_rsa_min_public_exponent = 65537
+    _fips_dsa_min_modulus = 1 << 2048
+    _fips_dh_min_key_size = 2048
+    _fips_dh_min_modulus = 1 << _fips_dh_min_key_size
+
     def __init__(self):
         self._binding = binding.Binding()
         self._ffi = self._binding.ffi
         self._lib = self._binding.lib
@@ -122,7 +146,8 @@
     def __init__(self):
         self._binding = binding.Binding()
         self._ffi = self._binding.ffi
         self._lib = self._binding.lib
+        self._fips_enabled = self._is_fips_enabled()
 
         self._cipher_registry = {}
         self._register_default_ciphers()
@@ -126,7 +151,13 @@
 
         self._cipher_registry = {}
         self._register_default_ciphers()
-        self.activate_osrandom_engine()
+        if self._fips_enabled and self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE:
+            warnings.warn(
+                "OpenSSL FIPS mode is enabled. Can't enable DRBG fork safety.",
+                UserWarning
+            )
+        else:
+            self.activate_osrandom_engine()
         self._dh_types = [self._lib.EVP_PKEY_DH]
         if self._lib.Cryptography_HAS_EVP_PKEY_DHX:
             self._dh_types.append(self._lib.EVP_PKEY_DHX)
@@ -134,6 +165,14 @@
     def openssl_assert(self, ok):
         return binding._openssl_assert(self._lib, ok)
 
+    def _is_fips_enabled(self):
+        fips_mode = getattr(self._lib, "FIPS_mode", lambda: 0)
+        mode = fips_mode()
+        if mode == 0:
+            # OpenSSL without FIPS pushes an error on the error stack
+            self._lib.ERR_clear_error()
+        return bool(mode)
+
     def activate_builtin_random(self):
         if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE:
             # Obtain a new structural reference.
@@ -222,6 +261,9 @@
         return evp_md
 
     def hash_supported(self, algorithm):
+        if self._fips_enabled and not isinstance(algorithm, self._fips_hashes):
+            return False
+
         evp_md = self._evp_md_from_algorithm(algorithm)
         return evp_md != self._ffi.NULL
 
@@ -232,6 +274,8 @@
         return _HashContext(self, algorithm)
 
     def cipher_supported(self, cipher, mode):
+        if self._fips_enabled and not isinstance(cipher, self._fips_ciphers):
+            return False
         try:
             adapter = self._cipher_registry[type(cipher), type(mode)]
         except KeyError:
@@ -1380,6 +1424,11 @@
                 errors[0]._lib_reason_match(
                     self._lib.ERR_LIB_EC,
                     self._lib.EC_R_UNKNOWN_GROUP
+                ) or
+                # This occurs in FIPS mode for unsupported curves on RHEL
+                errors[0]._lib_reason_match(
+                    self._lib.ERR_LIB_EC,
+                    self._lib.EC_R_NOT_A_NIST_PRIME
                 )
             )
             return False
@@ -1777,6 +1826,16 @@
 
         # TraditionalOpenSSL + PEM/DER
         if format is serialization.PrivateFormat.TraditionalOpenSSL:
+            if (
+                    self._fips_enabled and
+                    not isinstance(
+                        encryption_algorithm, serialization.NoEncryption
+                    )
+            ):
+                raise ValueError(
+                    "Encrypted traditional OpenSSL format is not "
+                    "supported in FIPS mode."
+                )
             key_type = self._lib.EVP_PKEY_id(evp_pkey)
 
             if encoding is serialization.Encoding.PEM:
@@ -2170,6 +2229,8 @@
         return _X25519PrivateKey(self, evp_pkey)
 
     def x25519_supported(self):
+        if self._fips_enabled:
+            return False
         return self._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
 
     def x448_load_public_bytes(self, data):
@@ -2200,6 +2261,8 @@
         return _X448PrivateKey(self, evp_pkey)
 
     def x448_supported(self):
+        if self._fips_enabled:
+            return False
         return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
 
     def ed25519_supported(self):
@@ -2203,6 +2266,8 @@
         return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
 
     def ed25519_supported(self):
+        if self._fips_enabled:
+            return False
         return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B
 
     def ed25519_load_public_bytes(self, data):
@@ -2238,6 +2303,8 @@
         return _Ed25519PrivateKey(self, evp_pkey)
 
     def ed448_supported(self):
+        if self._fips_enabled:
+            return False
         return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B
 
     def ed448_load_public_bytes(self, data):
@@ -2304,6 +2371,8 @@
 
     def aead_cipher_supported(self, cipher):
         cipher_name = aead._aead_cipher_name(cipher)
+        if self._fips_enabled and cipher_name not in self._fips_aead:
+            return False
         return (
             self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL
         )
@@ -2453,6 +2522,8 @@
         return self._read_mem_bio(bio)
 
     def poly1305_supported(self):
+        if self._fips_enabled:
+            return False
         return self._lib.Cryptography_HAS_POLY1305 == 1
 
     def create_poly1305_ctx(self, key):
diff --git a/tests/conftest.py b/tests/conftest.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvY29uZnRlc3QucHk=..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvY29uZnRlc3QucHk= 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -14,7 +14,10 @@
 
 
 def pytest_report_header(config):
-    return "OpenSSL: {}".format(openssl_backend.openssl_version_text())
+    return "\n".join([
+        "OpenSSL: {}".format(openssl_backend.openssl_version_text()),
+        "FIPS Enabled: {}".format(openssl_backend._fips_enabled),
+    ])
 
 
 def pytest_addoption(parser):
@@ -33,6 +36,12 @@
         metafunc.parametrize("wycheproof", testcases)
 
 
+def pytest_runtest_setup(item):
+    if openssl_backend._fips_enabled:
+        for marker in item.iter_markers(name="skip_fips"):
+            pytest.skip(marker.kwargs["reason"])
+
+
 @pytest.fixture()
 def backend(request):
     required_interfaces = [
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L2JhY2tlbmRzL3Rlc3Rfb3BlbnNzbC5weQ==..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L2JhY2tlbmRzL3Rlc3Rfb3BlbnNzbC5weQ== 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -171,6 +171,7 @@
 @pytest.mark.skipif(
     not backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE,
     reason="Requires OpenSSL with ENGINE support and OpenSSL < 1.1.1d")
+@pytest.mark.skip_fips(reason="osrandom engine disabled for FIPS")
 class TestOpenSSLRandomEngine(object):
     def setup(self):
         # The default RAND engine is global and shared between
diff --git a/tests/hazmat/backends/test_openssl_memleak.py b/tests/hazmat/backends/test_openssl_memleak.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L2JhY2tlbmRzL3Rlc3Rfb3BlbnNzbF9tZW1sZWFrLnB5..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L2JhY2tlbmRzL3Rlc3Rfb3BlbnNzbF9tZW1sZWFrLnB5 100644
--- a/tests/hazmat/backends/test_openssl_memleak.py
+++ b/tests/hazmat/backends/test_openssl_memleak.py
@@ -160,6 +160,7 @@
     )
 
 
+@pytest.mark.skip_fips(reason="FIPS self-test sets allow_customize = 0")
 @skip_if_memtesting_not_supported()
 class TestAssertNoMemoryLeaks(object):
     def test_no_leak_no_malloc(self):
@@ -205,6 +206,7 @@
             """))
 
 
+@pytest.mark.skip_fips(reason="FIPS self-test sets allow_customize = 0")
 @skip_if_memtesting_not_supported()
 class TestOpenSSLMemoryLeaks(object):
     @pytest.mark.parametrize("path", [
diff --git a/tests/hazmat/primitives/test_aead.py b/tests/hazmat/primitives/test_aead.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9hZWFkLnB5..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9hZWFkLnB5 100644
--- a/tests/hazmat/primitives/test_aead.py
+++ b/tests/hazmat/primitives/test_aead.py
@@ -364,5 +364,12 @@
             aesgcm.encrypt(nonce, b"", FakeData())
 
     @pytest.mark.parametrize("vector", _load_gcm_vectors())
-    def test_vectors(self, vector):
+    def test_vectors(self, backend, vector):
+        nonce = binascii.unhexlify(vector["iv"])
+
+        if backend._fips_enabled and len(nonce) != 12:
+            # Red Hat disables non-96-bit IV support as part of its FIPS
+            # patches.
+            pytest.skip("Non-96-bit IVs unsupported in FIPS mode.")
+
         key = binascii.unhexlify(vector["key"])
@@ -368,5 +375,4 @@
         key = binascii.unhexlify(vector["key"])
-        nonce = binascii.unhexlify(vector["iv"])
         aad = binascii.unhexlify(vector["aad"])
         ct = binascii.unhexlify(vector["ct"])
         pt = binascii.unhexlify(vector.get("pt", b""))
diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9kaC5weQ==..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9kaC5weQ== 100644
--- a/tests/hazmat/primitives/test_dh.py
+++ b/tests/hazmat/primitives/test_dh.py
@@ -196,6 +196,7 @@
                                                int(vector["g"], 16),
                                                int(vector["q"], 16))
 
+    @pytest.mark.skip_fips(reason="modulus too small for FIPS")
     @pytest.mark.parametrize("with_q", [False, True])
     def test_convert_to_numbers(self, backend, with_q):
         if with_q:
@@ -242,6 +243,7 @@
         with pytest.raises(ValueError):
             private.private_key(backend)
 
+    @pytest.mark.skip_fips(reason="FIPS requires key size >= 2048")
     @pytest.mark.parametrize("with_q", [False, True])
     def test_generate_dh(self, backend, with_q):
         if with_q:
@@ -309,6 +311,7 @@
 
         assert symkey == symkey_manual
 
+    @pytest.mark.skip_fips(reason="key_size too small for FIPS")
     def test_symmetric_key_padding(self, backend):
         """
         This test has specific parameters that produce a symmetric key
@@ -339,6 +342,11 @@
             os.path.join("asymmetric", "DH", "bad_exchange.txt"),
             load_nist_vectors))
     def test_bad_exchange(self, backend, vector):
+        if (
+                backend._fips_enabled and
+                int(vector["p1"]) < backend._fips_dh_min_modulus
+        ):
+            pytest.skip("modulus too small for FIPS mode")
         parameters1 = dh.DHParameterNumbers(int(vector["p1"]),
                                             int(vector["g"]))
         public1 = dh.DHPublicNumbers(int(vector["y1"]), parameters1)
@@ -370,6 +378,11 @@
             os.path.join("asymmetric", "DH", "vec.txt"),
             load_nist_vectors))
     def test_dh_vectors(self, backend, vector):
+        if (
+                backend._fips_enabled and
+                int(vector["p"]) < backend._fips_dh_min_modulus
+        ):
+            pytest.skip("modulus too small for FIPS mode")
         parameters = dh.DHParameterNumbers(int(vector["p"]),
                                            int(vector["g"]))
         public = dh.DHPublicNumbers(int(vector["y"]), parameters)
diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9kc2EucHk=..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9kc2EucHk= 100644
--- a/tests/hazmat/primitives/test_dsa.py
+++ b/tests/hazmat/primitives/test_dsa.py
@@ -23,6 +23,7 @@
 from .fixtures_dsa import (
     DSA_KEY_1024, DSA_KEY_2048, DSA_KEY_3072
 )
+from .utils import skip_fips_traditional_openssl
 from ...doubles import DummyHashAlgorithm, DummyKeySerializationEncryption
 from ...utils import (
     load_fips_dsa_key_pair_vectors, load_fips_dsa_sig_vectors,
@@ -49,7 +50,7 @@
 @pytest.mark.requires_backend_interface(interface=DSABackend)
 class TestDSA(object):
     def test_generate_dsa_parameters(self, backend):
-        parameters = dsa.generate_parameters(1024, backend)
+        parameters = dsa.generate_parameters(2048, backend)
         assert isinstance(parameters, dsa.DSAParameters)
 
     def test_generate_invalid_dsa_parameters(self, backend):
@@ -65,6 +66,11 @@
         )
     )
     def test_generate_dsa_keys(self, vector, backend):
+        if (
+            backend._fips_enabled and
+            vector['p'] < backend._fips_dsa_min_modulus
+        ):
+            pytest.skip("Small modulus blocked in FIPS mode")
         parameters = dsa.DSAParameterNumbers(
             p=vector['p'],
             q=vector['q'],
@@ -91,7 +97,7 @@
         )
 
     def test_generate_dsa_private_key_and_parameters(self, backend):
-        skey = dsa.generate_private_key(1024, backend)
+        skey = dsa.generate_private_key(2048, backend)
         assert skey
         numbers = skey.private_numbers()
         skey_parameters = numbers.public_numbers.parameter_numbers
@@ -718,6 +724,7 @@
         )
     )
     def test_private_bytes_encrypted_pem(self, backend, fmt, password):
+        skip_fips_traditional_openssl(backend, fmt)
         key_bytes = load_vectors_from_file(
             os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"),
             lambda pemfile: pemfile.read().encode()
@@ -812,6 +819,9 @@
         priv_num = key.private_numbers()
         assert loaded_priv_num == priv_num
 
+    @pytest.mark.skip_fips(
+        reason="Traditional OpenSSL key format is not supported in FIPS mode."
+    )
     @pytest.mark.parametrize(
         ("key_path", "encoding", "loader_func"),
         [
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9lYy5weQ==..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9lYy5weQ== 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -23,6 +23,7 @@
 from cryptography.utils import CryptographyDeprecationWarning
 
 from .fixtures_ec import EC_KEY_SECP384R1
+from .utils import skip_fips_traditional_openssl
 from ...doubles import DummyKeySerializationEncryption
 from ...utils import (
     load_fips_ecdsa_key_pair_vectors, load_fips_ecdsa_signing_vectors,
@@ -45,7 +46,7 @@
         curve_type()
     ):
         pytest.skip(
-            "ECDSA not supported with this hash {} and curve {}".format(
+            "ECDSA not supported with this hash {} and curve {}.".format(
                 hash_type().name, curve_type().name
             )
         )
@@ -693,6 +694,7 @@
         )
     )
     def test_private_bytes_encrypted_pem(self, backend, fmt, password):
+        skip_fips_traditional_openssl(backend, fmt)
         _skip_curve_unsupported(backend, ec.SECP256R1())
         key_bytes = load_vectors_from_file(
             os.path.join(
@@ -798,6 +800,9 @@
         priv_num = key.private_numbers()
         assert loaded_priv_num == priv_num
 
+    @pytest.mark.skip_fips(
+        reason="Traditional OpenSSL key format is not supported in FIPS mode."
+    )
     @pytest.mark.parametrize(
         ("key_path", "encoding", "loader_func"),
         [
diff --git a/tests/hazmat/primitives/test_pkcs12.py b/tests/hazmat/primitives/test_pkcs12.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9wa2NzMTIucHk=..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9wa2NzMTIucHk= 100644
--- a/tests/hazmat/primitives/test_pkcs12.py
+++ b/tests/hazmat/primitives/test_pkcs12.py
@@ -67,6 +67,7 @@
         only_if=lambda backend: backend.cipher_supported(_RC2(), None),
         skip_message="Does not support RC2"
     )
+    @pytest.mark.skip_fips(reason="Unsupported algorithm in FIPS mode")
     def test_load_pkcs12_ec_keys_rc2(self, filename, password, backend):
         self._test_load_pkcs12_ec_keys(filename, password, backend)
 
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9yc2EucHk=..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9yc2EucHk= 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -32,7 +32,8 @@
     RSA_KEY_745, RSA_KEY_768,
 )
 from .utils import (
-    _check_rsa_private_numbers, generate_rsa_verification_test
+    _check_rsa_private_numbers, generate_rsa_verification_test,
+    skip_fips_traditional_openssl
 )
 from ...doubles import (
     DummyAsymmetricPadding, DummyHashAlgorithm, DummyKeySerializationEncryption
@@ -152,6 +153,13 @@
         )
     )
     def test_generate_rsa_keys(self, backend, public_exponent, key_size):
+        if backend._fips_enabled:
+            if key_size < backend._fips_rsa_min_key_size:
+                pytest.skip("Key size not FIPS compliant: {}".format(key_size))
+            if public_exponent < backend._fips_rsa_min_public_exponent:
+                pytest.skip("Exponent not FIPS compliant: {}".format(
+                    public_exponent)
+                )
         skey = rsa.generate_private_key(public_exponent, key_size, backend)
         assert skey.key_size == key_size
 
@@ -2052,6 +2060,7 @@
         )
     )
     def test_private_bytes_encrypted_pem(self, backend, fmt, password):
+        skip_fips_traditional_openssl(backend, fmt)
         key = RSA_KEY_2048.private_key(backend)
         serialized = key.private_bytes(
             serialization.Encoding.PEM,
@@ -2138,6 +2147,9 @@
         priv_num = key.private_numbers()
         assert loaded_priv_num == priv_num
 
+    @pytest.mark.skip_fips(
+        reason="Traditional OpenSSL key format is not supported in FIPS mode."
+    )
     @pytest.mark.parametrize(
         ("key_path", "encoding", "loader_func"),
         [
diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9zZXJpYWxpemF0aW9uLnB5..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdGVzdF9zZXJpYWxpemF0aW9uLnB5 100644
--- a/tests/hazmat/primitives/test_serialization.py
+++ b/tests/hazmat/primitives/test_serialization.py
@@ -40,6 +40,14 @@
 from ...utils import raises_unsupported_algorithm
 
 
+def _skip_fips_format(key_path, password, backend):
+    if backend._fips_enabled:
+        if key_path[0] == "Traditional_OpenSSL_Serialization":
+            pytest.skip("Traditional OpenSSL format blocked in FIPS mode")
+        if key_path[0] == "PEM_Serialization" and password is not None:
+            pytest.skip("Encrypted PEM_Serialization blocked in FIPS mode")
+
+
 class TestBufferProtocolSerialization(object):
     @pytest.mark.requires_backend_interface(interface=RSABackend)
     @pytest.mark.parametrize(
@@ -79,6 +87,7 @@
         ]
     )
     def test_load_pem_rsa_private_key(self, key_path, password, backend):
+        _skip_fips_format(key_path, password, backend)
         data = load_vectors_from_file(
             os.path.join("asymmetric", *key_path),
             lambda pemfile: pemfile.read(), mode="rb"
@@ -404,6 +413,7 @@
         ]
     )
     def test_load_pem_rsa_private_key(self, key_file, password, backend):
+        _skip_fips_format(key_file, password, backend)
         key = load_vectors_from_file(
             os.path.join("asymmetric", *key_file),
             lambda pemfile: load_pem_private_key(
@@ -426,6 +436,7 @@
         ]
     )
     def test_load_dsa_private_key(self, key_path, password, backend):
+        _skip_fips_format(key_path, password, backend)
         key = load_vectors_from_file(
             os.path.join("asymmetric", *key_path),
             lambda pemfile: load_pem_private_key(
@@ -448,6 +459,7 @@
     @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
     def test_load_pem_ec_private_key(self, key_path, password, backend):
         _skip_curve_unsupported(backend, ec.SECP256R1())
+        _skip_fips_format(key_path, password, backend)
         key = load_vectors_from_file(
             os.path.join("asymmetric", *key_path),
             lambda pemfile: load_pem_private_key(
@@ -516,6 +528,9 @@
         assert key.curve.name == "secp256r1"
         assert key.curve.key_size == 256
 
+    @pytest.mark.skip_fips(
+        reason="Traditional OpenSSL format blocked in FIPS mode"
+    )
     def test_rsa_traditional_encrypted_values(self, backend):
         pkey = load_vectors_from_file(
             os.path.join(
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdXRpbHMucHk=..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvaGF6bWF0L3ByaW1pdGl2ZXMvdXRpbHMucHk= 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -14,6 +14,6 @@
     AlreadyFinalized, AlreadyUpdated, InvalidSignature, InvalidTag,
     NotYetFinalized
 )
-from cryptography.hazmat.primitives import hashes, hmac
+from cryptography.hazmat.primitives import hashes, hmac, serialization
 from cryptography.hazmat.primitives.asymmetric import rsa
 from cryptography.hazmat.primitives.ciphers import Cipher
@@ -18,5 +18,6 @@
 from cryptography.hazmat.primitives.asymmetric import rsa
 from cryptography.hazmat.primitives.ciphers import Cipher
+from cryptography.hazmat.primitives.ciphers.modes import GCM
 from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand
 from cryptography.hazmat.primitives.kdf.kbkdf import (
     CounterLocation, KBKDFHMAC, Mode
@@ -80,6 +81,15 @@
 
 
 def aead_test(backend, cipher_factory, mode_factory, params):
+    if (
+        mode_factory is GCM and backend._fips_enabled and
+        len(params["iv"]) != 24
+    ):
+        # Red Hat disables non-96-bit IV support as part of its FIPS
+        # patches. The check is for a byte length of 24 because the value is
+        # hex encoded.
+        pytest.skip("Non-96-bit IVs unsupported in FIPS mode.")
+
     if params.get("pt") is not None:
         plaintext = params["pt"]
     ciphertext = params["ct"]
@@ -470,3 +480,13 @@
     pkey = skey.public_numbers
     params = pkey.parameter_numbers
     assert pow(params.g, skey.x, params.p) == pkey.y
+
+
+def skip_fips_traditional_openssl(backend, fmt):
+    if (
+        fmt is serialization.PrivateFormat.TraditionalOpenSSL and
+        backend._fips_enabled
+    ):
+        pytest.skip(
+            "Traditional OpenSSL key format is not supported in FIPS mode."
+        )
diff --git a/tests/wycheproof/test_aes.py b/tests/wycheproof/test_aes.py
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dGVzdHMvd3ljaGVwcm9vZi90ZXN0X2Flcy5weQ==..7fde27822704d762e0422d02c10af49328e74159_dGVzdHMvd3ljaGVwcm9vZi90ZXN0X2Flcy5weQ== 100644
--- a/tests/wycheproof/test_aes.py
+++ b/tests/wycheproof/test_aes.py
@@ -55,6 +55,10 @@
     msg = binascii.unhexlify(wycheproof.testcase["msg"])
     ct = binascii.unhexlify(wycheproof.testcase["ct"])
     tag = binascii.unhexlify(wycheproof.testcase["tag"])
+    if backend._fips_enabled and len(iv) != 12:
+        # Red Hat disables non-96-bit IV support as part of its FIPS
+        # patches.
+        pytest.skip("Non-96-bit IVs unsupported in FIPS mode.")
     if wycheproof.valid or wycheproof.acceptable:
         enc = Cipher(algorithms.AES(key), modes.GCM(iv), backend).encryptor()
         enc.authenticate_additional_data(aad)
@@ -94,6 +98,10 @@
     msg = binascii.unhexlify(wycheproof.testcase["msg"])
     ct = binascii.unhexlify(wycheproof.testcase["ct"])
     tag = binascii.unhexlify(wycheproof.testcase["tag"])
+    if backend._fips_enabled and len(iv) != 12:
+        # Red Hat disables non-96-bit IV support as part of its FIPS
+        # patches.
+        pytest.skip("Non-96-bit IVs unsupported in FIPS mode.")
     aesgcm = AESGCM(key)
     if wycheproof.valid or wycheproof.acceptable:
         computed_ct = aesgcm.encrypt(iv, msg, aad)
diff --git a/tox.ini b/tox.ini
index 571d912fa409eea60e2f2ab2a5036804c481e2e4_dG94LmluaQ==..7fde27822704d762e0422d02c10af49328e74159_dG94LmluaQ== 100644
--- a/tox.ini
+++ b/tox.ini
@@ -13,7 +13,7 @@
     coverage
     ./vectors
     randomorder: pytest-randomly
-passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING
+passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING OPENSSL_FORCE_FIPS_MODE
 commands =
     pip list
     # We use parallel mode and then combine here so that coverage.py will take
@@ -86,5 +86,6 @@
 addopts = -r s
 markers =
     requires_backend_interface: this test requires a specific backend interface
+    skip_fips: this test is not executed in FIPS mode
     supported: parametrized test requiring only_if and skip_message
     wycheproof_tests: this test runs a wycheproof fixture