mirror of
https://github.com/python/cpython
synced 2024-10-07 03:08:22 +00:00
gh-109109: Expose retrieving certificate chains in SSL module (#109113)
Adds APIs to get the TLS certificate chains, verified or full unverified, from SSLSocket and SSLObject. Co-authored-by: Gregory P. Smith [Google LLC] <greg@krypto.org>
This commit is contained in:
parent
ddf2e953c2
commit
5a740cd06e
|
@ -43,8 +43,10 @@ This module provides a class, :class:`ssl.SSLSocket`, which is derived from the
|
|||
:class:`socket.socket` type, and provides a socket-like wrapper that also
|
||||
encrypts and decrypts the data going over the socket with SSL. It supports
|
||||
additional methods such as :meth:`getpeercert`, which retrieves the
|
||||
certificate of the other side of the connection, and :meth:`cipher`, which
|
||||
retrieves the cipher being used for the secure connection.
|
||||
certificate of the other side of the connection, :meth:`cipher`, which
|
||||
retrieves the cipher being used for the secure connection or
|
||||
:meth:`get_verified_chain`, :meth:`get_unverified_chain` which retrieves
|
||||
certificate chain.
|
||||
|
||||
For more sophisticated applications, the :class:`ssl.SSLContext` class
|
||||
helps manage settings and certificates, which can then be inherited
|
||||
|
@ -1210,6 +1212,22 @@ SSL sockets also have the following additional methods and attributes:
|
|||
.. versionchanged:: 3.9
|
||||
IPv6 address strings no longer have a trailing new line.
|
||||
|
||||
.. method:: SSLSocket.get_verified_chain()
|
||||
|
||||
Returns verified certificate chain provided by the other
|
||||
end of the SSL channel as a list of DER-encoded bytes.
|
||||
If certificate verification was disabled method acts the same as
|
||||
:meth:`~SSLSocket.get_unverified_chain`.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. method:: SSLSocket.get_unverified_chain()
|
||||
|
||||
Returns raw certificate chain provided by the other
|
||||
end of the SSL channel as a list of DER-encoded bytes.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. method:: SSLSocket.cipher()
|
||||
|
||||
Returns a three-value tuple containing the name of the cipher being used, the
|
||||
|
@ -1656,8 +1674,9 @@ to speed up repeated connections from the same clients.
|
|||
Due to the early negotiation phase of the TLS connection, only limited
|
||||
methods and attributes are usable like
|
||||
:meth:`SSLSocket.selected_alpn_protocol` and :attr:`SSLSocket.context`.
|
||||
The :meth:`SSLSocket.getpeercert`,
|
||||
:meth:`SSLSocket.cipher` and :meth:`SSLSocket.compression` methods require that
|
||||
The :meth:`SSLSocket.getpeercert`, :meth:`SSLSocket.get_verified_chain`,
|
||||
:meth:`SSLSocket.get_unverified_chain` :meth:`SSLSocket.cipher`
|
||||
and :meth:`SSLSocket.compression` methods require that
|
||||
the TLS connection has progressed beyond the TLS Client Hello and therefore
|
||||
will not return meaningful values nor can they be called safely.
|
||||
|
||||
|
@ -2414,6 +2433,8 @@ provided.
|
|||
- :meth:`~SSLSocket.read`
|
||||
- :meth:`~SSLSocket.write`
|
||||
- :meth:`~SSLSocket.getpeercert`
|
||||
- :meth:`~SSLSocket.get_verified_chain`
|
||||
- :meth:`~SSLSocket.get_unverified_chain`
|
||||
- :meth:`~SSLSocket.selected_alpn_protocol`
|
||||
- :meth:`~SSLSocket.selected_npn_protocol`
|
||||
- :meth:`~SSLSocket.cipher`
|
||||
|
|
33
Lib/ssl.py
33
Lib/ssl.py
|
@ -876,6 +876,31 @@ def getpeercert(self, binary_form=False):
|
|||
"""
|
||||
return self._sslobj.getpeercert(binary_form)
|
||||
|
||||
def get_verified_chain(self):
|
||||
"""Returns verified certificate chain provided by the other
|
||||
end of the SSL channel as a list of DER-encoded bytes.
|
||||
|
||||
If certificate verification was disabled method acts the same as
|
||||
``SSLSocket.get_unverified_chain``.
|
||||
"""
|
||||
chain = self._sslobj.get_verified_chain()
|
||||
|
||||
if chain is None:
|
||||
return []
|
||||
|
||||
return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain]
|
||||
|
||||
def get_unverified_chain(self):
|
||||
"""Returns raw certificate chain provided by the other
|
||||
end of the SSL channel as a list of DER-encoded bytes.
|
||||
"""
|
||||
chain = self._sslobj.get_unverified_chain()
|
||||
|
||||
if chain is None:
|
||||
return []
|
||||
|
||||
return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain]
|
||||
|
||||
def selected_npn_protocol(self):
|
||||
"""Return the currently selected NPN protocol as a string, or ``None``
|
||||
if a next protocol was not negotiated or if NPN is not supported by one
|
||||
|
@ -1129,6 +1154,14 @@ def getpeercert(self, binary_form=False):
|
|||
self._check_connected()
|
||||
return self._sslobj.getpeercert(binary_form)
|
||||
|
||||
@_sslcopydoc
|
||||
def get_verified_chain(self):
|
||||
return self._sslobj.get_verified_chain()
|
||||
|
||||
@_sslcopydoc
|
||||
def get_unverified_chain(self):
|
||||
return self._sslobj.get_unverified_chain()
|
||||
|
||||
@_sslcopydoc
|
||||
def selected_npn_protocol(self):
|
||||
self._checkClosed()
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
You can now get the raw TLS certificate chains from TLS connections via
|
||||
:meth:`ssl.SSLSocket.get_verified_chain` and
|
||||
:meth:`ssl.SSLSocket.get_unverified_chain` methods.
|
||||
|
||||
Contributed by Mateusz Nowak.
|
Loading…
Reference in a new issue