Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-148292: Update ssl._SSLSocket for OpenSSL 4#149102
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
+136
−0
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
a05a9ce
gh-148292: Update ssl._SSLSocket for OpenSSL 4
vstinner f803408
Fix doc formatting (NEWS entry)
vstinner cac2565
Skip sendfile() test if the SSL socket has no sendfile() method
vstinner ec5bb40
Use also got_eof_error in do_handshake()
vstinner 43ef40c
Update comment
vstinner b852eef
Fix shutdown() test on OpenSSL 1.1.1
vstinner 49a1209
Fix fill_and_set_sslerror() for NULL sslsock
vstinner 278cefd
Enhance test
vstinner 66db041
Mention ssl.SSLObject in the NEWS entry
vstinner 0f650cc
Apply suggestions from code review
vstinner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -2843,6 +2843,36 @@ def close(self): | ||
| def stop(self): | ||
| self.active = False | ||
| class TestEOFServer(threading.Thread): | ||
| def __init__(self): | ||
| super().__init__() | ||
| self.listening = threading.Event() | ||
| self.address = None | ||
| def run(self): | ||
| context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) | ||
| context.load_cert_chain(CERTFILE) | ||
| server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| with server_sock: | ||
| server_sock.settimeout(support.SHORT_TIMEOUT) | ||
| server_sock.bind((HOST, 0)) | ||
| server_sock.listen(5) | ||
| self.address = server_sock.getsockname() | ||
| self.listening.set() | ||
| sock, addr = server_sock.accept() | ||
| sslconn = context.wrap_socket(sock, server_side=True) | ||
| with sslconn: | ||
| request = b'' | ||
| while chunk := sslconn.recv(1024): | ||
| request += chunk | ||
| if b'\n' in chunk: | ||
| break | ||
| sslconn.sendall(b'server\n') | ||
| sslconn.shutdown(socket.SHUT_WR) | ||
| class AsyncoreEchoServer(threading.Thread): | ||
| # this one's based on asyncore.dispatcher | ||
| @@ -5001,6 +5031,58 @@ def background(sock): | ||
| if cm.exc_value is not None: | ||
| raise cm.exc_value | ||
| def test_got_eof(self): | ||
| # gh-148292: Test that _ssl._SSLSocket behaves the same on all OpenSSL | ||
| # versions on calling methods after EOF (after the first SSLEOFError). | ||
| server = TestEOFServer() | ||
| server.start() | ||
vstinner marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if not server.listening.wait(support.SHORT_TIMEOUT): | ||
| raise RuntimeError("server took too long") | ||
| self.addCleanup(server.join) | ||
| context = ssl.create_default_context(cafile=CERTFILE) | ||
| sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| sock.settimeout(support.SHORT_TIMEOUT) | ||
| sock.connect(server.address) | ||
| sslsock = context.wrap_socket(sock, server_hostname='localhost') | ||
| with sslsock: | ||
| sslsock.sendall(b'client\n') | ||
| # test the _ssl._SSLSocket object, not ssl.SSLSocket | ||
| sslobj = sslsock._sslobj | ||
| data = sslobj.read(1024) | ||
| self.assertEqual(data, b'server\n') | ||
| # The second read gets EOF error and sets got_eof_error to 1 | ||
| with self.assertRaises(ssl.SSLEOFError): | ||
| sslobj.read(1024) | ||
| # Following read(), sendfile(), write() and do_handshake() calls | ||
| # must raise SSLEOFError | ||
| with self.assertRaises(ssl.SSLEOFError): | ||
| # The _SSLSocket remembers the previous EOF error | ||
| # and raises again SSLEOFError | ||
| sslobj.read(1024) | ||
| if hasattr(sslobj, 'sendfile'): | ||
| with open(__file__, "rb") as fp: | ||
| with self.assertRaises(ssl.SSLEOFError): | ||
| sslobj.sendfile(fp.fileno(), 0, 1) | ||
| with self.assertRaises(ssl.SSLEOFError): | ||
| sslobj.write(b'client2\n') | ||
| with self.assertRaises(ssl.SSLEOFError): | ||
| sslsock.do_handshake() | ||
| self.assertEqual(sslsock.pending(), 0) | ||
| try: | ||
| sslsock.shutdown(socket.SHUT_WR) | ||
| except OSError as exc: | ||
| self.assertEqual(exc.errno, errno.ENOTCONN) | ||
| else: | ||
| # On Windows and on OpenSSL 1.1.1, shutdown() doesn't | ||
| # raise an error | ||
| pass | ||
| @unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA, | ||
| "Test needs TLS 1.3 PHA") | ||
7 changes: 7 additions & 0 deletions
7 Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| :mod:`ssl`: Update :class:`ssl.SSLSocket` and :class:`ssl.SSLObject` for | ||
| OpenSSL 4. The classes now remember if they get a :exc:`ssl.SSLEOFError`. In this | ||
| case, following :meth:`~ssl.SSLSocket.read`, :meth:`!sendfile`, | ||
| :meth:`~ssl.SSLSocket.write`, and :meth:`~ssl.SSLSocket.do_handshake` calls | ||
| raise :exc:`ssl.SSLEOFError` without calling the underlying OpenSSL function. | ||
| Thanks to that, :class:`ssl.SSLSocket` behaves the same on all OpenSSL versions | ||
| on EOF. Patch by Victor Stinner. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.