summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/ssl.rst29
-rw-r--r--Lib/ssl.py33
-rw-r--r--Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst5
3 files changed, 63 insertions, 4 deletions
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 5d6bc82..92cf3de 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -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`
diff --git a/Lib/ssl.py b/Lib/ssl.py
index c4c5a4c..62e5585 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -876,6 +876,31 @@ class SSLObject:
"""
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
@@ -1130,6 +1155,14 @@ class SSLSocket(socket):
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()
warnings.warn(
diff --git a/Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst b/Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst
new file mode 100644
index 0000000..e741e60
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst
@@ -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.