mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-108310: Fix CVE-2023-40217: Check for & avoid the ssl pre-close flaw (#108315)
Instances of `ssl.SSLSocket` were vulnerable to a bypass of the TLS handshake and included protections (like certificate verification) and treating sent unencrypted data as if it were post-handshake TLS encrypted data. The vulnerability is caused when a socket is connected, data is sent by the malicious peer and stored in a buffer, and then the malicious peer closes the socket within a small timing window before the other peers’ TLS handshake can begin. After this sequence of events the closed socket will not immediately attempt a TLS handshake due to not being connected but will also allow the buffered data to be read as if a successful TLS handshake had occurred. Co-authored-by: Gregory P. Smith [Google LLC] <greg@krypto.org>
This commit is contained in:
parent
d2879f2095
commit
0cb0c238d5
3 changed files with 248 additions and 1 deletions
31
Lib/ssl.py
31
Lib/ssl.py
|
@ -975,7 +975,7 @@ class SSLSocket(socket):
|
|||
)
|
||||
self = cls.__new__(cls, **kwargs)
|
||||
super(SSLSocket, self).__init__(**kwargs)
|
||||
self.settimeout(sock.gettimeout())
|
||||
sock_timeout = sock.gettimeout()
|
||||
sock.detach()
|
||||
|
||||
self._context = context
|
||||
|
@ -994,9 +994,38 @@ class SSLSocket(socket):
|
|||
if e.errno != errno.ENOTCONN:
|
||||
raise
|
||||
connected = False
|
||||
blocking = self.getblocking()
|
||||
self.setblocking(False)
|
||||
try:
|
||||
# We are not connected so this is not supposed to block, but
|
||||
# testing revealed otherwise on macOS and Windows so we do
|
||||
# the non-blocking dance regardless. Our raise when any data
|
||||
# is found means consuming the data is harmless.
|
||||
notconn_pre_handshake_data = self.recv(1)
|
||||
except OSError as e:
|
||||
# EINVAL occurs for recv(1) on non-connected on unix sockets.
|
||||
if e.errno not in (errno.ENOTCONN, errno.EINVAL):
|
||||
raise
|
||||
notconn_pre_handshake_data = b''
|
||||
self.setblocking(blocking)
|
||||
if notconn_pre_handshake_data:
|
||||
# This prevents pending data sent to the socket before it was
|
||||
# closed from escaping to the caller who could otherwise
|
||||
# presume it came through a successful TLS connection.
|
||||
reason = "Closed before TLS handshake with data in recv buffer."
|
||||
notconn_pre_handshake_data_error = SSLError(e.errno, reason)
|
||||
# Add the SSLError attributes that _ssl.c always adds.
|
||||
notconn_pre_handshake_data_error.reason = reason
|
||||
notconn_pre_handshake_data_error.library = None
|
||||
try:
|
||||
self.close()
|
||||
except OSError:
|
||||
pass
|
||||
raise notconn_pre_handshake_data_error
|
||||
else:
|
||||
connected = True
|
||||
|
||||
self.settimeout(sock_timeout) # Must come after setblocking() calls.
|
||||
self._connected = connected
|
||||
if connected:
|
||||
# create the SSL object
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue