From 460a19d45425218c34dcb7d6fde478f80a987fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= Date: Wed, 16 May 2018 19:44:19 +0200 Subject: Add Connection.get_certificate method (#733) This makes it possible to retrieve the local certificate (if any) for a Connection. An example where this is useful is when negotiating a DTLS-SRTP connection, the fingerprint of the local certificate needs to be communicated to the remote party out-of-band via SDP. --- CHANGELOG.rst | 2 ++ src/OpenSSL/SSL.py | 12 ++++++++++++ tests/test_ssl.py | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0d8765f..1a659a0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,8 @@ Deprecations: Changes: ^^^^^^^^ +- Added ``Connection.get_certificate`` to retrieve the local certificate. + `#733 `_ - ``OpenSSL.SSL.Connection`` now sets ``SSL_MODE_AUTO_RETRY`` by default. `#753 `_ - Added ``Context.set_tlsext_use_srtp`` to enable negotiation of SRTP keying material. diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index 4c708ba..e3eddae 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -2176,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) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index b09fce7..0831904 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -2418,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 -- cgit v1.2.1