Repository: pyca/pyopenssl
Pull request #1347 (2024-08-05 11:56:25)

Deprecated passing X509 objects to `add_client_ca`
Added support for passing cryptography.x509.Certificate

Refs https://github.com/pyca/pyopenssl/issues/1321

alex: (If this LGTY, please merge :-))

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 587c8fd..e14baa0 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,7 +15,7 @@ Deprecations:
 
 - Deprecated ``OpenSSL.rand`` - callers should use ``os.urandom()`` instead.
 - Deprecated ``OpenSSL.crypto.get_elliptic_curves`` and ``OpenSSL.crypto.get_elliptic_curve``, as well as passing the reult of them to ``OpenSSL.SSL.Context.set_tmp_ecdh``, users should instead pass curves from ``cryptography``.
-- Deprecated passing ``X509`` objects to ``OpenSSL.SSL.Context.use_certificate``, ``OpenSSL.SSL.Connection.use_certificate``, and ``OpenSSL.SSL.Context.add_extra_chain_cert``, users should instead pass ``cryptography.x509.Certificate`` instances. This is in preparation for deprecating pyOpenSSL's ``X509`` entirely.
+- Deprecated passing ``X509`` objects to ``OpenSSL.SSL.Context.use_certificate``, ``OpenSSL.SSL.Connection.use_certificate``, ``OpenSSL.SSL.Context.add_extra_chain_cert``, and ``OpenSSL.SSL.Context.add_client_ca``, users should instead pass ``cryptography.x509.Certificate`` instances. This is in preparation for deprecating pyOpenSSL's ``X509`` entirely.
 
 Changes:
 ^^^^^^^^
diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py
index ab41b3a..4d17a9d 100644
--- a/src/OpenSSL/SSL.py
+++ b/src/OpenSSL/SSL.py
@@ -1492,7 +1492,9 @@ class Context:
 
         _lib.SSL_CTX_set_client_CA_list(self._context, name_stack)
 
-    def add_client_ca(self, certificate_authority: X509) -> None:
+    def add_client_ca(
+        self, certificate_authority: X509 | x509.Certificate
+    ) -> None:
         """
         Add the CA certificate to the list of preferred signers for this
         context.
@@ -1506,7 +1508,18 @@ class Context:
         .. versionadded:: 0.10
         """
         if not isinstance(certificate_authority, X509):
-            raise TypeError("certificate_authority must be an X509 instance")
+            certificate_authority = X509.from_cryptography(
+                certificate_authority
+            )
+        else:
+            warnings.warn(
+                (
+                    "Passing pyOpenSSL X509 objects is deprecated. You "
+                    "should use a cryptography.x509.Certificate instead."
+                ),
+                DeprecationWarning,
+                stacklevel=2,
+            )
 
         add_result = _lib.SSL_CTX_add_client_CA(
             self._context, certificate_authority._x509


Test patch:
diff --git a/tests/test_ssl.py b/tests/test_ssl.py
index 15156bb..c3618fa 100644
--- a/tests/test_ssl.py
+++ b/tests/test_ssl.py
@@ -3922,7 +3922,7 @@ class TestMemoryBIO:
 
         def multiple_ca(ctx):
             ctx.add_client_ca(cacert)
-            ctx.add_client_ca(secert)
+            ctx.add_client_ca(secert.to_cryptography())
             return [cadesc, sedesc]
 
         self._check_client_ca_list(multiple_ca)
@@ -3962,7 +3962,7 @@ class TestMemoryBIO:
         sedesc = secert.get_subject()
 
         def set_replaces_add_ca(ctx):
-            ctx.add_client_ca(clcert)
+            ctx.add_client_ca(clcert.to_cryptography())
             ctx.set_client_ca_list([cadesc])
             ctx.add_client_ca(secert)
             return [cadesc, sedesc]