Repository: pyca/pyopenssl
Pull request #1352 (2024-08-09 16:02:23)

Allow Connection.get_peer_certificate to return a cryptography certificate
refs https://github.com/pyca/pyopenssl/issues/1321


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 443a06c..81e1b22 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -21,7 +21,7 @@ Deprecations:
 Changes:
 ^^^^^^^^
 
-* ``OpenSSL.SSL.Connection.get_certificate`` now takes an ``as_cryptography`` keyword-argument. When ``True`` is passed then a ``cryptography.x509.Certificate`` is returned, instead of an ``OpenSSL.crypto.X509``. In the future, passing ``False`` (the default) will be deprecated.
+* ``OpenSSL.SSL.Connection.get_certificate`` and ``OpenSSL.SSL.Connection.get_peer_certificate`` now take an ``as_cryptography`` keyword-argument. When ``True`` is passed then a ``cryptography.x509.Certificate`` is returned, instead of an ``OpenSSL.crypto.X509``. In the future, passing ``False`` (the default) will be deprecated.
 
 
 24.2.1 (2024-07-20)
diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py
index a25be26..b420880 100644
--- a/src/OpenSSL/SSL.py
+++ b/src/OpenSSL/SSL.py
@@ -2708,14 +2708,10 @@ class Connection:
     ) -> X509 | None:
         pass
 
-    @typing.overload
     def get_certificate(
-        self, *, as_cryptography: bool = False
-    ) -> X509 | x509.Certificate | None:
-        pass
-
-    def get_certificate(
-        self, *, as_cryptography: bool = False
+        self,
+        *,
+        as_cryptography: typing.Literal[True] | typing.Literal[False] = False,
     ) -> X509 | x509.Certificate | None:
         """
         Retrieve the local certificate (if any)
@@ -2735,15 +2731,38 @@ class Connection:
             return pycert
         return None
 
-    def get_peer_certificate(self) -> X509 | None:
+    @typing.overload
+    def get_peer_certificate(
+        self, *, as_cryptography: typing.Literal[True]
+    ) -> x509.Certificate | None:
+        pass
+
+    @typing.overload
+    def get_peer_certificate(
+        self, *, as_cryptography: typing.Literal[False] = False
+    ) -> X509 | None:
+        pass
+
+    def get_peer_certificate(
+        self,
+        *,
+        as_cryptography: typing.Literal[True] | typing.Literal[False] = False,
+    ) -> X509 | x509.Certificate | None:
         """
         Retrieve the other side's certificate (if any)
 
+        :param bool as_cryptography: Controls whether a
+            ``cryptography.x509.Certificate`` or an ``OpenSSL.crypto.X509``
+            object should be returned.
+
         :return: The peer's certificate
         """
         cert = _lib.SSL_get_peer_certificate(self._ssl)
         if cert != _ffi.NULL:
-            return X509._from_raw_x509_ptr(cert)
+            pycert = X509._from_raw_x509_ptr(cert)
+            if as_cryptography:
+                return pycert.to_cryptography()
+            return pycert
         return None
 
     @staticmethod


Test patch:
diff --git a/tests/test_ssl.py b/tests/test_ssl.py
index 9be03b0..caf7b8f 100644
--- a/tests/test_ssl.py
+++ b/tests/test_ssl.py
@@ -1073,6 +1073,14 @@ class TestContext:
         cert = clientSSL.get_peer_certificate()
         assert cert.get_subject().CN == "Testing Root CA"
 
+        cryptography_cert = clientSSL.get_peer_certificate(
+            as_cryptography=True
+        )
+        assert (
+            cryptography_cert.subject.rfc4514_string()
+            == "CN=Testing Root CA,O=Testing,L=Chicago,ST=IL,C=US"
+        )
+
     def _load_verify_cafile(self, cafile):
         """
         Verify that if path to a file containing a certificate is passed to