Repository: pyca/pyopenssl
Pull request #759 (2018-05-16 16:27:25)

tell people to stop using this where possible


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index ab28dcb..1a659a0 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -24,8 +24,12 @@ Deprecations:
 Changes:
 ^^^^^^^^
 
+- Added ``Connection.get_certificate`` to retrieve the local certificate.
+  `#733 <https://github.com/pyca/pyopenssl/pull/733>`_
 - ``OpenSSL.SSL.Connection`` now sets ``SSL_MODE_AUTO_RETRY`` by default.
   `#753 <https://github.com/pyca/pyopenssl/pull/753>`_
+- Added ``Context.set_tlsext_use_srtp`` to enable negotiation of SRTP keying material.
+  `#734 <https://github.com/pyca/pyopenssl/pull/734>`_
 
 
 ----
diff --git a/README.rst b/README.rst
index 36046ca..ed078d4 100644
--- a/README.rst
+++ b/README.rst
@@ -14,8 +14,11 @@ pyOpenSSL -- A Python wrapper around the OpenSSL library
    :target: https://codecov.io/github/pyca/pyopenssl
    :alt: Test coverage
 
+**Note:** The Python Cryptographic Authority **strongly suggests** the use of `pyca/cryptography`_
+where possible. If you are using pyOpenSSL for anything other than making a TLS connection 
+**you should move to cryptography and drop your pyOpenSSL dependency**.
 
-High-level wrapper around a subset of the OpenSSL library.  Includes
+High-level wrapper around a subset of the OpenSSL library. Includes
 
 * ``SSL.Connection`` objects, wrapping the methods of Python's portable sockets
 * Callbacks written in Python
@@ -41,3 +44,4 @@ You can also join ``#cryptography-dev`` on Freenode to ask questions or get invo
 .. _`issue tracker`: https://github.com/pyca/pyopenssl/issues
 .. _cryptography-dev: https://mail.python.org/mailman/listinfo/cryptography-dev
 .. _GitHub: https://github.com/pyca/pyopenssl
+.. _`pyca/cryptography`: https://github.com/pyca/cryptography
diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py
index 1bf6450..e3eddae 100644
--- a/src/OpenSSL/SSL.py
+++ b/src/OpenSSL/SSL.py
@@ -1371,6 +1371,21 @@ class Context(object):
         _lib.SSL_CTX_set_tlsext_servername_callback(
             self._context, self._tlsext_servername_callback)
 
+    def set_tlsext_use_srtp(self, profiles):
+        """
+        Enable support for negotiating SRTP keying material.
+
+        :param bytes profiles: A colon delimited list of protection profile
+            names, like ``b'SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32'``.
+        :return: None
+        """
+        if not isinstance(profiles, bytes):
+            raise TypeError("profiles must be a byte string.")
+
+        _openssl_assert(
+            _lib.SSL_CTX_set_tlsext_use_srtp(self._context, profiles) == 0
+        )
+
     @_requires_npn
     def set_npn_advertise_callback(self, callback):
         """
@@ -2024,7 +2039,7 @@ class Connection(object):
             result.append(pyname)
         return result
 
-    def makefile(self):
+    def makefile(self, *args, **kwargs):
         """
         The makefile() method is not implemented, since there is no dup
         semantics for SSL connections
@@ -2161,6 +2176,18 @@ class Connection(object):
         """
         return self._socket.shutdown(*args, **kwargs)
 
+    def get_certificate(self):
+        """
+        Retrieve the local certificate (if any)
+
+        :return: The local certificate
+        """
+        cert = _lib.SSL_get_certificate(self._ssl)
+        if cert != _ffi.NULL:
+            _lib.X509_up_ref(cert)
+            return X509._from_raw_x509_ptr(cert)
+        return None
+
     def get_peer_certificate(self):
         """
         Retrieve the other side's certificate (if any)


Test patch:
diff --git a/tests/test_ssl.py b/tests/test_ssl.py
index 87bd18c..0831904 100644
--- a/tests/test_ssl.py
+++ b/tests/test_ssl.py
@@ -1593,6 +1593,35 @@ class TestContext(object):
         store = context.get_cert_store()
         assert isinstance(store, X509Store)
 
+    def test_set_tlsext_use_srtp_not_bytes(self):
+        """
+        `Context.set_tlsext_use_srtp' enables negotiating SRTP keying material.
+
+        It raises a TypeError if the list of profiles is not a byte string.
+        """
+        context = Context(TLSv1_METHOD)
+        with pytest.raises(TypeError):
+            context.set_tlsext_use_srtp(text_type('SRTP_AES128_CM_SHA1_80'))
+
+    def test_set_tlsext_use_srtp_invalid_profile(self):
+        """
+        `Context.set_tlsext_use_srtp' enables negotiating SRTP keying material.
+
+        It raises an Error if the call to OpenSSL fails.
+        """
+        context = Context(TLSv1_METHOD)
+        with pytest.raises(Error):
+            context.set_tlsext_use_srtp(b'SRTP_BOGUS')
+
+    def test_set_tlsext_use_srtp_valid(self):
+        """
+        `Context.set_tlsext_use_srtp' enables negotiating SRTP keying material.
+
+        It does not return anything.
+        """
+        context = Context(TLSv1_METHOD)
+        assert context.set_tlsext_use_srtp(b'SRTP_AES128_CM_SHA1_80') is None
+
 
 class TestServerNameCallback(object):
     """
@@ -2389,6 +2418,31 @@ class TestConnection(object):
         with pytest.raises(NotImplementedError):
             conn.makefile()
 
+    def test_get_certificate(self):
+        """
+        `Connection.get_certificate` returns the local certificate.
+        """
+        chain = _create_certificate_chain()
+        [(cakey, cacert), (ikey, icert), (skey, scert)] = chain
+
+        context = Context(TLSv1_METHOD)
+        context.use_certificate(scert)
+        client = Connection(context, None)
+        cert = client.get_certificate()
+        assert cert is not None
+        assert "Server Certificate" == cert.get_subject().CN
+
+    def test_get_certificate_none(self):
+        """
+        `Connection.get_certificate` returns the local certificate.
+
+        If there is no certificate, it returns None.
+        """
+        context = Context(TLSv1_METHOD)
+        client = Connection(context, None)
+        cert = client.get_certificate()
+        assert cert is None
+
     def test_get_peer_cert_chain(self):
         """
         `Connection.get_peer_cert_chain` returns a list of certificates