From cea1f2e60948847996a6af0d30787ce4492e8fe6 Mon Sep 17 00:00:00 2001
From: Alex Gaynor <alex.gaynor@gmail.com>
Date: Sat, 9 Mar 2024 18:06:12 -0500
Subject: [PATCH] Remove deprecated PKCS12 and NetscapeSPKI classes (#1288)

---
 CHANGELOG.rst         |  16 +++
 doc/api/crypto.rst    |  18 ---
 src/OpenSSL/crypto.py | 300 ----------------------------------------
 tests/test_crypto.py  | 314 ------------------------------------------
 4 files changed, 16 insertions(+), 632 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 7f6d60c0e..7a7958b8a 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -4,6 +4,22 @@ Changelog
 Versions are year-based with a strict backward-compatibility policy.
 The third digit is only for regressions.
 
+24.1.0 (UNRELEASED)
+-------------------
+
+Backward-incompatible changes:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Removed the deprecated ``OpenSSL.crypto.PKCS12`` and
+  ``OpenSSL.crypto.NetscapeSPKI``. ``OpenSSL.crypto.PKCS12`` may be replaced
+  by the PKCS#12 APIs in the ``cryptography`` package.
+
+Deprecations:
+^^^^^^^^^^^^^
+
+Changes:
+^^^^^^^^
+
 24.0.0 (2024-01-22)
 -------------------
 
diff --git a/doc/api/crypto.rst b/doc/api/crypto.rst
index 56eeb8315..926ae5809 100644
--- a/doc/api/crypto.rst
+++ b/doc/api/crypto.rst
@@ -160,14 +160,6 @@ PKey objects
 
     Key type constants.
 
-.. _openssl-pkcs12:
-
-PKCS12 objects
---------------
-
-.. autoclass:: PKCS12
-               :members:
-
 .. _openssl-509ext:
 
 X509Extension objects
@@ -178,16 +170,6 @@ X509Extension objects
                :special-members:
                :exclude-members: __weakref__
 
-.. _openssl-netscape-spki:
-
-NetscapeSPKI objects
---------------------
-
-.. autoclass:: NetscapeSPKI
-               :members:
-               :special-members:
-               :exclude-members: __weakref__
-
 .. _crl:
 
 CRL objects
diff --git a/src/OpenSSL/crypto.py b/src/OpenSSL/crypto.py
index 1707488c7..80a6c1958 100644
--- a/src/OpenSSL/crypto.py
+++ b/src/OpenSSL/crypto.py
@@ -77,8 +77,6 @@
     "dump_privatekey",
     "Revoked",
     "CRL",
-    "PKCS12",
-    "NetscapeSPKI",
     "load_publickey",
     "load_privatekey",
     "dump_certificate_request",
@@ -2617,304 +2615,6 @@ def export(
 )
 
 
-class PKCS12:
-    """
-    A PKCS #12 archive.
-    """
-
-    def __init__(self) -> None:
-        self._pkey: Optional[PKey] = None
-        self._cert: Optional[X509] = None
-        self._cacerts: Optional[List[X509]] = None
-        self._friendlyname: Optional[bytes] = None
-
-    def get_certificate(self) -> Optional[X509]:
-        """
-        Get the certificate in the PKCS #12 structure.
-
-        :return: The certificate, or :py:const:`None` if there is none.
-        :rtype: :py:class:`X509` or :py:const:`None`
-        """
-        return self._cert
-
-    def set_certificate(self, cert: X509) -> None:
-        """
-        Set the certificate in the PKCS #12 structure.
-
-        :param cert: The new certificate, or :py:const:`None` to unset it.
-        :type cert: :py:class:`X509` or :py:const:`None`
-
-        :return: ``None``
-        """
-        if not isinstance(cert, X509):
-            raise TypeError("cert must be an X509 instance")
-        self._cert = cert
-
-    def get_privatekey(self) -> Optional[PKey]:
-        """
-        Get the private key in the PKCS #12 structure.
-
-        :return: The private key, or :py:const:`None` if there is none.
-        :rtype: :py:class:`PKey`
-        """
-        return self._pkey
-
-    def set_privatekey(self, pkey: PKey) -> None:
-        """
-        Set the certificate portion of the PKCS #12 structure.
-
-        :param pkey: The new private key, or :py:const:`None` to unset it.
-        :type pkey: :py:class:`PKey` or :py:const:`None`
-
-        :return: ``None``
-        """
-        if not isinstance(pkey, PKey):
-            raise TypeError("pkey must be a PKey instance")
-        self._pkey = pkey
-
-    def get_ca_certificates(self) -> Optional[Tuple[X509, ...]]:
-        """
-        Get the CA certificates in the PKCS #12 structure.
-
-        :return: A tuple with the CA certificates in the chain, or
-            :py:const:`None` if there are none.
-        :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
-        """
-        if self._cacerts is not None:
-            return tuple(self._cacerts)
-        return None
-
-    def set_ca_certificates(self, cacerts: Optional[Iterable[X509]]) -> None:
-        """
-        Replace or set the CA certificates within the PKCS12 object.
-
-        :param cacerts: The new CA certificates, or :py:const:`None` to unset
-            them.
-        :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
-
-        :return: ``None``
-        """
-        if cacerts is None:
-            self._cacerts = None
-        else:
-            cacerts = list(cacerts)
-            for cert in cacerts:
-                if not isinstance(cert, X509):
-                    raise TypeError(
-                        "iterable must only contain X509 instances"
-                    )
-            self._cacerts = cacerts
-
-    def set_friendlyname(self, name: Optional[bytes]) -> None:
-        """
-        Set the friendly name in the PKCS #12 structure.
-
-        :param name: The new friendly name, or :py:const:`None` to unset.
-        :type name: :py:class:`bytes` or :py:const:`None`
-
-        :return: ``None``
-        """
-        if name is None:
-            self._friendlyname = None
-        elif not isinstance(name, bytes):
-            raise TypeError(
-                f"name must be a byte string or None (not {name!r})"
-            )
-        self._friendlyname = name
-
-    def get_friendlyname(self) -> Optional[bytes]:
-        """
-        Get the friendly name in the PKCS# 12 structure.
-
-        :returns: The friendly name,  or :py:const:`None` if there is none.
-        :rtype: :py:class:`bytes` or :py:const:`None`
-        """
-        return self._friendlyname
-
-    def export(
-        self,
-        passphrase: Optional[bytes] = None,
-        iter: int = 2048,
-        maciter: int = 1,
-    ) -> bytes:
-        """
-        Dump a PKCS12 object as a string.
-
-        For more information, see the :c:func:`PKCS12_create` man page.
-
-        :param passphrase: The passphrase used to encrypt the structure. Unlike
-            some other passphrase arguments, this *must* be a string, not a
-            callback.
-        :type passphrase: :py:data:`bytes`
-
-        :param iter: Number of times to repeat the encryption step.
-        :type iter: :py:data:`int`
-
-        :param maciter: Number of times to repeat the MAC step.
-        :type maciter: :py:data:`int`
-
-        :return: The string representation of the PKCS #12 structure.
-        :rtype:
-        """
-        passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
-
-        if self._cacerts is None:
-            cacerts = _ffi.NULL
-        else:
-            cacerts = _lib.sk_X509_new_null()
-            cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
-            for cert in self._cacerts:
-                _lib.sk_X509_push(cacerts, cert._x509)
-
-        if passphrase is None:
-            passphrase = _ffi.NULL
-
-        friendlyname = self._friendlyname
-        if friendlyname is None:
-            friendlyname = _ffi.NULL
-
-        if self._pkey is None:
-            pkey = _ffi.NULL
-        else:
-            pkey = self._pkey._pkey
-
-        if self._cert is None:
-            cert = _ffi.NULL
-        else:
-            cert = self._cert._x509
-
-        pkcs12 = _lib.PKCS12_create(
-            passphrase,
-            friendlyname,
-            pkey,
-            cert,
-            cacerts,
-            _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
-            _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
-            iter,
-            maciter,
-            0,
-        )
-        if pkcs12 == _ffi.NULL:
-            _raise_current_error()
-        pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
-
-        bio = _new_mem_buf()
-        _lib.i2d_PKCS12_bio(bio, pkcs12)
-        return _bio_to_string(bio)
-
-
-utils.deprecated(
-    PKCS12,
-    __name__,
-    (
-        "PKCS#12 support in pyOpenSSL is deprecated. You should use the APIs "
-        "in cryptography."
-    ),
-    DeprecationWarning,
-    name="PKCS12",
-)
-
-
-class NetscapeSPKI:
-    """
-    A Netscape SPKI object.
-    """
-
-    def __init__(self) -> None:
-        spki = _lib.NETSCAPE_SPKI_new()
-        self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
-
-    def sign(self, pkey: PKey, digest: str) -> None:
-        """
-        Sign the certificate request with this key and digest type.
-
-        :param pkey: The private key to sign with.
-        :type pkey: :py:class:`PKey`
-
-        :param digest: The message digest to use.
-        :type digest: :py:class:`str`
-
-        :return: ``None``
-        """
-        if pkey._only_public:
-            raise ValueError("Key has only public part")
-
-        if not pkey._initialized:
-            raise ValueError("Key is uninitialized")
-
-        digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
-        if digest_obj == _ffi.NULL:
-            raise ValueError("No such digest method")
-
-        sign_result = _lib.NETSCAPE_SPKI_sign(
-            self._spki, pkey._pkey, digest_obj
-        )
-        _openssl_assert(sign_result > 0)
-
-    def verify(self, key: PKey) -> bool:
-        """
-        Verifies a signature on a certificate request.
-
-        :param PKey key: The public key that signature is supposedly from.
-
-        :return: ``True`` if the signature is correct.
-        :rtype: bool
-
-        :raises OpenSSL.crypto.Error: If the signature is invalid, or there was
-            a problem verifying the signature.
-        """
-        answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
-        if answer <= 0:
-            _raise_current_error()
-        return True
-
-    def b64_encode(self) -> bytes:
-        """
-        Generate a base64 encoded representation of this SPKI object.
-
-        :return: The base64 encoded string.
-        :rtype: :py:class:`bytes`
-        """
-        encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
-        result = _ffi.string(encoded)
-        _lib.OPENSSL_free(encoded)
-        return result
-
-    def get_pubkey(self) -> PKey:
-        """
-        Get the public key of this certificate.
-
-        :return: The public key.
-        :rtype: :py:class:`PKey`
-        """
-        pkey = PKey.__new__(PKey)
-        pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
-        _openssl_assert(pkey._pkey != _ffi.NULL)
-        pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
-        pkey._only_public = True
-        return pkey
-
-    def set_pubkey(self, pkey: PKey) -> None:
-        """
-        Set the public key of the certificate
-
-        :param pkey: The public key
-        :return: ``None``
-        """
-        set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
-        _openssl_assert(set_result == 1)
-
-
-utils.deprecated(
-    NetscapeSPKI,
-    __name__,
-    "NetscapeSPKI support in pyOpenSSL is deprecated.",
-    DeprecationWarning,
-    name="NetscapeSPKI",
-)
-
-
 class _PassphraseHelper:
     def __init__(
         self,
diff --git a/tests/test_crypto.py b/tests/test_crypto.py
index 76d6be631..c0f809e53 100644
--- a/tests/test_crypto.py
+++ b/tests/test_crypto.py
@@ -50,8 +50,6 @@
 with pytest.warns(DeprecationWarning):
     from OpenSSL.crypto import (
         CRL,
-        PKCS12,
-        NetscapeSPKI,
         Revoked,
         X509Extension,
         dump_crl,
@@ -2337,273 +2335,6 @@ def test_load_locations_raises_error_on_failure(self, tmpdir):
             store.load_locations(cafile=str(invalid_ca_file))
 
 
-class TestPKCS12:
-    """
-    Test for `OpenSSL.crypto.PKCS12`.
-    """
-
-    def test_type(self):
-        """
-        `PKCS12` is a type object.
-        """
-        assert is_consistent_type(PKCS12, "PKCS12")
-
-    def test_empty_construction(self):
-        """
-        `PKCS12` returns a new instance of `PKCS12` with no certificate,
-        private key, CA certificates, or friendly name.
-        """
-        p12 = PKCS12()
-        assert None is p12.get_certificate()
-        assert None is p12.get_privatekey()
-        assert None is p12.get_ca_certificates()
-        assert None is p12.get_friendlyname()
-
-    def test_type_errors(self):
-        """
-        The `PKCS12` setter functions (`set_certificate`, `set_privatekey`,
-        `set_ca_certificates`, and `set_friendlyname`) raise `TypeError`
-        when passed objects of types other than those expected.
-        """
-        p12 = PKCS12()
-        for bad_arg in [3, PKey(), X509]:
-            with pytest.raises(TypeError):
-                p12.set_certificate(bad_arg)
-        for bad_arg in [3, "legbone", X509()]:
-            with pytest.raises(TypeError):
-                p12.set_privatekey(bad_arg)
-        for bad_arg in [3, X509(), (3, 4), (PKey(),)]:
-            with pytest.raises(TypeError):
-                p12.set_ca_certificates(bad_arg)
-        for bad_arg in [6, ("foo", "bar")]:
-            with pytest.raises(TypeError):
-                p12.set_friendlyname(bad_arg)
-
-    def test_key_only(self):
-        """
-        A `PKCS12` with only a private key can be exported using
-        `PKCS12.export`.
-        """
-        passwd = b"blah"
-        p12 = PKCS12()
-        pkey = load_privatekey(FILETYPE_PEM, root_key_pem)
-        p12.set_privatekey(pkey)
-        assert None is p12.get_certificate()
-        assert pkey == p12.get_privatekey()
-        p12.export(passphrase=passwd, iter=2, maciter=3)
-
-    def test_cert_only(self):
-        """
-        A `PKCS12` with only a certificate can be exported using
-        `PKCS12.export`.
-        """
-        passwd = b"blah"
-        p12 = PKCS12()
-        cert = load_certificate(FILETYPE_PEM, root_cert_pem)
-        p12.set_certificate(cert)
-        assert cert == p12.get_certificate()
-        assert None is p12.get_privatekey()
-        p12.export(passphrase=passwd, iter=2, maciter=3)
-
-    def gen_pkcs12(self, cert_pem=None, key_pem=None, ca_pem=None):
-        """
-        Generate a PKCS12 object with components from PEM.  Verify that the set
-        functions return None.
-        """
-        p12 = PKCS12()
-
-        ret = p12.set_certificate(load_certificate(FILETYPE_PEM, cert_pem))
-        assert ret is None
-
-        ret = p12.set_privatekey(load_privatekey(FILETYPE_PEM, key_pem))
-        assert ret is None
-
-        if ca_pem:
-            ret = p12.set_ca_certificates(
-                (load_certificate(FILETYPE_PEM, ca_pem),)
-            )
-            assert ret is None
-        return p12
-
-    def check_recovery(
-        self, p12_str, key=None, cert=None, ca=None, passwd=b"", extra=()
-    ):
-        """
-        Use openssl program to confirm three components are recoverable from a
-        PKCS12 string.
-        """
-        recovered_key = _runopenssl(
-            p12_str,
-            b"pkcs12",
-            b"-nocerts",
-            b"-nodes",
-            b"-passin",
-            b"pass:" + passwd,
-            *extra,
-        ).replace(b"\r\n", b"\n")
-        assert recovered_key[-len(key) :] == key
-
-        recovered_cert = _runopenssl(
-            p12_str,
-            b"pkcs12",
-            b"-clcerts",
-            b"-nodes",
-            b"-passin",
-            b"pass:" + passwd,
-            b"-nokeys",
-            *extra,
-        ).replace(b"\r\n", b"\n")
-        assert recovered_cert[-len(cert) :] == cert
-
-        if ca:
-            recovered_cert = _runopenssl(
-                p12_str,
-                b"pkcs12",
-                b"-cacerts",
-                b"-nodes",
-                b"-passin",
-                b"pass:" + passwd,
-                b"-nokeys",
-                *extra,
-            ).replace(b"\r\n", b"\n")
-            assert recovered_cert[-len(ca) :] == ca
-
-    def test_replace(self):
-        """
-        `PKCS12.set_certificate` replaces the certificate in a PKCS12
-        cluster. `PKCS12.set_privatekey` replaces the private key.
-        `PKCS12.set_ca_certificates` replaces the CA certificates.
-        """
-        p12 = self.gen_pkcs12(client_cert_pem, client_key_pem, root_cert_pem)
-        p12.set_certificate(load_certificate(FILETYPE_PEM, server_cert_pem))
-        p12.set_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
-        root_cert = load_certificate(FILETYPE_PEM, root_cert_pem)
-        client_cert = load_certificate(FILETYPE_PEM, client_cert_pem)
-        p12.set_ca_certificates([root_cert])  # not a tuple
-        assert 1 == len(p12.get_ca_certificates())
-        assert root_cert == p12.get_ca_certificates()[0]
-        p12.set_ca_certificates([client_cert, root_cert])
-        assert 2 == len(p12.get_ca_certificates())
-        assert client_cert == p12.get_ca_certificates()[0]
-        assert root_cert == p12.get_ca_certificates()[1]
-
-    def test_friendly_name(self):
-        """
-        The *friendlyName* of a PKCS12 can be set and retrieved via
-        `PKCS12.get_friendlyname` and `PKCS12_set_friendlyname`, and a
-        `PKCS12` with a friendly name set can be dumped with `PKCS12.export`.
-        """
-        passwd = b'Dogmeat[]{}!@#$%^&*()~`?/.,<>-_+=";:'
-        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
-        for friendly_name in [b"Serverlicious", None, b"###"]:
-            p12.set_friendlyname(friendly_name)
-            assert p12.get_friendlyname() == friendly_name
-            p12.export(passphrase=passwd, iter=2, maciter=3)
-
-    def test_various_empty_passphrases(self):
-        """
-        Test that missing, None, and '' passphrases are identical for PKCS12
-        export.
-        """
-        p12 = self.gen_pkcs12(client_cert_pem, client_key_pem, root_cert_pem)
-        passwd = b""
-        dumped_p12_empty = p12.export(iter=2, maciter=0, passphrase=passwd)
-        dumped_p12_none = p12.export(iter=3, maciter=2, passphrase=None)
-        dumped_p12_nopw = p12.export(iter=9, maciter=4)
-        for dumped_p12 in [dumped_p12_empty, dumped_p12_none, dumped_p12_nopw]:
-            self.check_recovery(
-                dumped_p12,
-                key=client_key_pem,
-                cert=client_cert_pem,
-                ca=root_cert_pem,
-                passwd=passwd,
-            )
-
-    def test_removing_ca_cert(self):
-        """
-        Passing `None` to `PKCS12.set_ca_certificates` removes all CA
-        certificates.
-        """
-        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
-        p12.set_ca_certificates(None)
-        assert None is p12.get_ca_certificates()
-
-    def test_export_without_mac(self):
-        """
-        Exporting a PKCS12 with a `maciter` of `-1` excludes the MAC entirely.
-        """
-        passwd = b"Lake Michigan"
-        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
-        dumped_p12 = p12.export(maciter=-1, passphrase=passwd, iter=2)
-        self.check_recovery(
-            dumped_p12,
-            key=server_key_pem,
-            cert=server_cert_pem,
-            passwd=passwd,
-            extra=(b"-nomacver",),
-        )
-
-    def test_load_without_mac(self):
-        """
-        Loading a PKCS12 without a MAC does something other than crash.
-        """
-        passwd = b"Lake Michigan"
-        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
-        p12.export(maciter=-1, passphrase=passwd, iter=2)
-
-    def test_zero_len_list_for_ca(self):
-        """
-        A PKCS12 with an empty CA certificates list can be exported.
-        """
-        passwd = b"Hobie 18"
-        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem)
-        p12.set_ca_certificates([])
-        assert () == p12.get_ca_certificates()
-        dumped_p12 = p12.export(passphrase=passwd, iter=3)
-        self.check_recovery(
-            dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=passwd
-        )
-
-    def test_export_without_args(self):
-        """
-        All the arguments to `PKCS12.export` are optional.
-        """
-        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
-        dumped_p12 = p12.export()  # no args
-        self.check_recovery(
-            dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=b""
-        )
-
-    def test_export_without_bytes(self):
-        """
-        Test `PKCS12.export` with text not bytes as passphrase
-        """
-        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
-
-        with pytest.warns(DeprecationWarning) as w:
-            warnings.simplefilter("always")
-            dumped_p12 = p12.export(passphrase=b"randomtext".decode("ascii"))
-            msg = "{} for passphrase is no longer accepted, use bytes".format(
-                WARNING_TYPE_EXPECTED
-            )
-            assert msg == str(w[-1].message)
-        self.check_recovery(
-            dumped_p12,
-            key=server_key_pem,
-            cert=server_cert_pem,
-            passwd=b"randomtext",
-        )
-
-    def test_key_cert_mismatch(self):
-        """
-        `PKCS12.export` raises an exception when a key and certificate
-        mismatch.
-        """
-        p12 = self.gen_pkcs12(server_cert_pem, client_key_pem, root_cert_pem)
-        with pytest.raises(Error):
-            p12.export()
-
-
 def _runopenssl(pem, *args):
     """
     Run the command line openssl tool with the given arguments and write
@@ -3073,51 +2804,6 @@ def test_bad_certificate(self):
             load_certificate(FILETYPE_ASN1, b"lol")
 
 
-class TestNetscapeSPKI(_PKeyInteractionTestsMixin):
-    """
-    Tests for `OpenSSL.crypto.NetscapeSPKI`.
-    """
-
-    def signable(self):
-        """
-        Return a new `NetscapeSPKI` for use with signing tests.
-        """
-        return NetscapeSPKI()
-
-    def test_type(self):
-        """
-        `NetscapeSPKI` can be used to create instances of that type.
-        """
-        assert is_consistent_type(NetscapeSPKI, "NetscapeSPKI")
-
-    def test_construction(self):
-        """
-        `NetscapeSPKI` returns an instance of `NetscapeSPKI`.
-        """
-        nspki = NetscapeSPKI()
-        assert isinstance(nspki, NetscapeSPKI)
-
-    def test_invalid_attribute(self):
-        """
-        Accessing a non-existent attribute of a `NetscapeSPKI` instance
-        causes an `AttributeError` to be raised.
-        """
-        nspki = NetscapeSPKI()
-        with pytest.raises(AttributeError):
-            nspki.foo
-
-    def test_b64_encode(self):
-        """
-        `NetscapeSPKI.b64_encode` encodes the certificate to a base64 blob.
-        """
-        nspki = NetscapeSPKI()
-        pkey = load_privatekey(FILETYPE_PEM, root_key_pem)
-        nspki.set_pubkey(pkey)
-        nspki.sign(pkey, GOOD_DIGEST)
-        blob = nspki.b64_encode()
-        assert isinstance(blob, bytes)
-
-
 class TestRevoked:
     """
     Tests for `OpenSSL.crypto.Revoked`.