Skip to content

gh-118658: Return consistent types from get_un/verified_chain in SSLObject and SSLSocket #118669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
dae06d1
Expose retrieving certificate chains in SSL module
matiuszka Sep 7, 2023
676f9b1
Merge branch 'main' into main
matiuszka Sep 7, 2023
1418dd1
Review remarks applied
matiuszka Sep 8, 2023
0cdfe19
Trim white spaces
matiuszka Sep 8, 2023
4a51db2
Review fixes.
matiuszka Sep 11, 2023
6206f4f
Merge branch 'main' into main
matiuszka Sep 12, 2023
701c62a
Update Lib/ssl.py
matiuszka Sep 13, 2023
4c31619
Merge branch 'main' into main
matiuszka Sep 19, 2023
f925937
Review fixes
matiuszka Sep 19, 2023
5cb139d
NEWS entry.
gpshead Sep 20, 2023
45a19dc
Merge branch 'python:main' into main
matiuszka May 6, 2024
d276aeb
Return consistent types for `get_un/verified_chain` in `SSLObject` an…
matiuszka May 6, 2024
0d15ad0
Merge branch 'main' into main
matiuszka May 6, 2024
0574858
Merge branch 'main' into main
matiuszka May 7, 2024
3039cc7
Merge branch 'main' into main
matiuszka May 9, 2024
c690d4d
Merge branch 'main' into main
matiuszka May 13, 2024
c29d0fe
Merge branch 'main' into main
matiuszka May 17, 2024
c1a55be
Merge branch 'main' into main
matiuszka May 22, 2024
b3aeb06
Merge branch 'main' into main
matiuszka Jul 14, 2024
10ab5f0
Merge branch 'main' into main
matiuszka Jul 17, 2024
19bf5f1
Simple test for un/verified chain
matiuszka Aug 7, 2024
d962206
Merge branch 'main' into main
matiuszka Aug 7, 2024
c8c8fcb
Merge branch 'main' into main
matiuszka Aug 7, 2024
44166ad
Merge branch 'main' into main
matiuszka Aug 14, 2024
e0a1dc6
Tests improvements
matiuszka Aug 14, 2024
f2c6a18
Merge branch 'main' into main
matiuszka Aug 14, 2024
5595d6e
Merge branch 'main' into main
matiuszka Aug 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions Lib/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1164,11 +1164,21 @@ def getpeercert(self, binary_form=False):

@_sslcopydoc
def get_verified_chain(self):
return self._sslobj.get_verified_chain()
chain = self._sslobj.get_verified_chain()

if chain is None:
return []

return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain]

@_sslcopydoc
def get_unverified_chain(self):
return self._sslobj.get_unverified_chain()
chain = self._sslobj.get_unverified_chain()

if chain is None:
return []

return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain]

@_sslcopydoc
def selected_npn_protocol(self):
Expand Down
34 changes: 34 additions & 0 deletions Lib/test/certdata/cert3.pem

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions Lib/test/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def data_file(*name):

# Two keys and certs signed by the same CA (for SNI tests)
SIGNED_CERTFILE = data_file("keycert3.pem")
SINGED_CERTFILE_ONLY = data_file("cert3.pem")
SIGNED_CERTFILE_HOSTNAME = 'localhost'

SIGNED_CERTFILE_INFO = {
Expand Down Expand Up @@ -4720,6 +4721,40 @@ def test_internal_chain_client(self):
ssl.PEM_cert_to_DER_cert(pem), der
)

def test_certificate_chain(self):
client_context, server_context, hostname = testing_context(
server_chain=False
)
server = ThreadedEchoServer(context=server_context, chatty=False)

with open(SIGNING_CA) as f:
expected_ca_cert = ssl.PEM_cert_to_DER_cert(f.read())

with open(SINGED_CERTFILE_ONLY) as f:
expected_ee_cert = ssl.PEM_cert_to_DER_cert(f.read())

with server:
with client_context.wrap_socket(
socket.socket(),
server_hostname=hostname
) as s:
s.connect((HOST, server.port))
vc = s.get_verified_chain()
self.assertEqual(len(vc), 2)

ee, ca = vc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add asserts that ee and ca are both of type bytes. Otherwise the test would also pass without the changes in Lib/ssl.py.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposed improvement applied.

self.assertIsInstance(ee, bytes)
self.assertIsInstance(ca, bytes)
self.assertEqual(expected_ca_cert, ca)
self.assertEqual(expected_ee_cert, ee)

uvc = s.get_unverified_chain()
self.assertEqual(len(uvc), 1)
self.assertIsInstance(uvc[0], bytes)

self.assertEqual(ee, uvc[0])
self.assertNotEqual(ee, ca)

def test_internal_chain_server(self):
client_context, server_context, hostname = testing_context()
client_context.load_cert_chain(SIGNED_CERTFILE)
Expand Down
Original file line number Diff line number Diff line change
@@ -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