Skip to content

Commit

Permalink
Add Connection.get_certificate method
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jlaine committed Feb 13, 2018
1 parent 3d231f0 commit 8b7bc04
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 1 deletion.
3 changes: 2 additions & 1 deletion CHANGELOG.rst
Expand Up @@ -23,7 +23,8 @@ Deprecations:
Changes:
^^^^^^^^

*none*
- Added ``Connection.get_certificate`` to retrieve the local certificate.
`#733 <https://github.com/pyca/pyopenssl/pull/733>`_


----
Expand Down
2 changes: 2 additions & 0 deletions doc/api/ssl.rst
Expand Up @@ -629,6 +629,8 @@ Connection objects have the following methods:
Specify a replacement Context object for this Connection.


.. automethod:: Connection.get_certificate

.. py:method:: Connection.get_peer_certificate()
Retrieve the other side's certificate (if any)
Expand Down
12 changes: 12 additions & 0 deletions src/OpenSSL/SSL.py
Expand Up @@ -2063,6 +2063,18 @@ def sock_shutdown(self, *args, **kwargs):
"""
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)
Expand Down
25 changes: 25 additions & 0 deletions tests/test_ssl.py
Expand Up @@ -2392,6 +2392,31 @@ def test_makefile(self):
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
Expand Down

0 comments on commit 8b7bc04

Please sign in to comment.