mirror of
https://github.com/python/cpython.git
synced 2025-08-01 07:33:08 +00:00
incorporate fixes from issue 3162; SSL doc patch
This commit is contained in:
parent
996b9f38db
commit
61c001a939
3 changed files with 163 additions and 7 deletions
|
@ -327,9 +327,10 @@ SSLSocket Objects
|
||||||
Performs the SSL shutdown handshake, which removes the TLS layer
|
Performs the SSL shutdown handshake, which removes the TLS layer
|
||||||
from the underlying socket, and returns the underlying socket
|
from the underlying socket, and returns the underlying socket
|
||||||
object. This can be used to go from encrypted operation over a
|
object. This can be used to go from encrypted operation over a
|
||||||
connection to unencrypted. The returned socket should always be
|
connection to unencrypted. The socket instance returned should always be
|
||||||
used for further communication with the other side of the
|
used for further communication with the other side of the
|
||||||
connection, rather than the original socket
|
connection, rather than the original socket instance (which may
|
||||||
|
not function properly after the unwrap).
|
||||||
|
|
||||||
.. index:: single: certificates
|
.. index:: single: certificates
|
||||||
|
|
||||||
|
|
44
Lib/ssl.py
44
Lib/ssl.py
|
@ -91,10 +91,12 @@ class SSLSocket (socket):
|
||||||
suppress_ragged_eofs=True):
|
suppress_ragged_eofs=True):
|
||||||
socket.__init__(self, _sock=sock._sock)
|
socket.__init__(self, _sock=sock._sock)
|
||||||
# the initializer for socket trashes the methods (tsk, tsk), so...
|
# the initializer for socket trashes the methods (tsk, tsk), so...
|
||||||
self.send = lambda x, flags=0: SSLSocket.send(self, x, flags)
|
self.send = lambda data, flags=0: SSLSocket.send(self, data, flags)
|
||||||
self.recv = lambda x, flags=0: SSLSocket.recv(self, x, flags)
|
|
||||||
self.sendto = lambda data, addr, flags=0: SSLSocket.sendto(self, data, addr, flags)
|
self.sendto = lambda data, addr, flags=0: SSLSocket.sendto(self, data, addr, flags)
|
||||||
self.recvfrom = lambda addr, buflen, flags: SSLSocket.recvfrom(self, addr, buflen, flags)
|
self.recv = lambda buflen=1024, flags=0: SSLSocket.recv(self, buflen, flags)
|
||||||
|
self.recvfrom = lambda addr, buflen=1024, flags=0: SSLSocket.recvfrom(self, addr, buflen, flags)
|
||||||
|
self.recv_into = lambda buffer, nbytes=None, flags=0: SSLSocket.recv_into(self, buffer, nbytes, flags)
|
||||||
|
self.recvfrom_into = lambda buffer, nbytes=None, flags=0: SSLSocket.recvfrom_into(self, buffer, nbytes, flags)
|
||||||
|
|
||||||
if certfile and not keyfile:
|
if certfile and not keyfile:
|
||||||
keyfile = certfile
|
keyfile = certfile
|
||||||
|
@ -221,6 +223,30 @@ class SSLSocket (socket):
|
||||||
else:
|
else:
|
||||||
return socket.recv(self, buflen, flags)
|
return socket.recv(self, buflen, flags)
|
||||||
|
|
||||||
|
def recv_into (self, buffer, nbytes=None, flags=0):
|
||||||
|
if buffer and (nbytes is None):
|
||||||
|
nbytes = len(buffer)
|
||||||
|
elif nbytes is None:
|
||||||
|
nbytes = 1024
|
||||||
|
if self._sslobj:
|
||||||
|
if flags != 0:
|
||||||
|
raise ValueError(
|
||||||
|
"non-zero flags not allowed in calls to recv_into() on %s" %
|
||||||
|
self.__class__)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
tmp_buffer = self.read(nbytes)
|
||||||
|
v = len(tmp_buffer)
|
||||||
|
buffer[:v] = tmp_buffer
|
||||||
|
return v
|
||||||
|
except SSLError as x:
|
||||||
|
if x.args[0] == SSL_ERROR_WANT_READ:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise x
|
||||||
|
else:
|
||||||
|
return socket.recv_into(self, buffer, nbytes, flags)
|
||||||
|
|
||||||
def recvfrom (self, addr, buflen=1024, flags=0):
|
def recvfrom (self, addr, buflen=1024, flags=0):
|
||||||
if self._sslobj:
|
if self._sslobj:
|
||||||
raise ValueError("recvfrom not allowed on instances of %s" %
|
raise ValueError("recvfrom not allowed on instances of %s" %
|
||||||
|
@ -228,6 +254,13 @@ class SSLSocket (socket):
|
||||||
else:
|
else:
|
||||||
return socket.recvfrom(self, addr, buflen, flags)
|
return socket.recvfrom(self, addr, buflen, flags)
|
||||||
|
|
||||||
|
def recvfrom_into (self, buffer, nbytes=None, flags=0):
|
||||||
|
if self._sslobj:
|
||||||
|
raise ValueError("recvfrom_into not allowed on instances of %s" %
|
||||||
|
self.__class__)
|
||||||
|
else:
|
||||||
|
return socket.recvfrom_into(self, buffer, nbytes, flags)
|
||||||
|
|
||||||
def pending (self):
|
def pending (self):
|
||||||
if self._sslobj:
|
if self._sslobj:
|
||||||
return self._sslobj.pending()
|
return self._sslobj.pending()
|
||||||
|
@ -295,8 +328,9 @@ class SSLSocket (socket):
|
||||||
|
|
||||||
def makefile(self, mode='r', bufsize=-1):
|
def makefile(self, mode='r', bufsize=-1):
|
||||||
|
|
||||||
"""Ouch. Need to make and return a file-like object that
|
"""Make and return a file-like object that
|
||||||
works with the SSL connection."""
|
works with the SSL connection. Just use the code
|
||||||
|
from the socket module."""
|
||||||
|
|
||||||
self._makefile_refs += 1
|
self._makefile_refs += 1
|
||||||
return _fileobject(self, mode, bufsize)
|
return _fileobject(self, mode, bufsize)
|
||||||
|
|
|
@ -1030,6 +1030,127 @@ else:
|
||||||
server.join()
|
server.join()
|
||||||
|
|
||||||
|
|
||||||
|
def testAllRecvAndSendMethods(self):
|
||||||
|
|
||||||
|
if test_support.verbose:
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
|
server = ThreadedEchoServer(CERTFILE,
|
||||||
|
certreqs=ssl.CERT_NONE,
|
||||||
|
ssl_version=ssl.PROTOCOL_TLSv1,
|
||||||
|
cacerts=CERTFILE,
|
||||||
|
chatty=True,
|
||||||
|
connectionchatty=False)
|
||||||
|
flag = threading.Event()
|
||||||
|
server.start(flag)
|
||||||
|
# wait for it to start
|
||||||
|
flag.wait()
|
||||||
|
# try to connect
|
||||||
|
try:
|
||||||
|
s = ssl.wrap_socket(socket.socket(),
|
||||||
|
server_side=False,
|
||||||
|
certfile=CERTFILE,
|
||||||
|
ca_certs=CERTFILE,
|
||||||
|
cert_reqs=ssl.CERT_NONE,
|
||||||
|
ssl_version=ssl.PROTOCOL_TLSv1)
|
||||||
|
s.connect((HOST, server.port))
|
||||||
|
except ssl.SSLError as x:
|
||||||
|
raise support.TestFailed("Unexpected SSL error: " + str(x))
|
||||||
|
except Exception as x:
|
||||||
|
raise support.TestFailed("Unexpected exception: " + str(x))
|
||||||
|
else:
|
||||||
|
# helper methods for standardising recv* method signatures
|
||||||
|
def _recv_into():
|
||||||
|
b = bytearray("\0"*100)
|
||||||
|
count = s.recv_into(b)
|
||||||
|
return b[:count]
|
||||||
|
|
||||||
|
def _recvfrom_into():
|
||||||
|
b = bytearray("\0"*100)
|
||||||
|
count, addr = s.recvfrom_into(b)
|
||||||
|
return b[:count]
|
||||||
|
|
||||||
|
# (name, method, whether to expect success, *args)
|
||||||
|
send_methods = [
|
||||||
|
('send', s.send, True, []),
|
||||||
|
('sendto', s.sendto, False, ["some.address"]),
|
||||||
|
('sendall', s.sendall, True, []),
|
||||||
|
]
|
||||||
|
recv_methods = [
|
||||||
|
('recv', s.recv, True, []),
|
||||||
|
('recvfrom', s.recvfrom, False, ["some.address"]),
|
||||||
|
('recv_into', _recv_into, True, []),
|
||||||
|
('recvfrom_into', _recvfrom_into, False, []),
|
||||||
|
]
|
||||||
|
data_prefix = u"PREFIX_"
|
||||||
|
|
||||||
|
for meth_name, send_meth, expect_success, args in send_methods:
|
||||||
|
indata = data_prefix + meth_name
|
||||||
|
try:
|
||||||
|
send_meth(indata.encode('ASCII', 'strict'), *args)
|
||||||
|
outdata = s.read()
|
||||||
|
outdata = outdata.decode('ASCII', 'strict')
|
||||||
|
if outdata != indata.lower():
|
||||||
|
raise support.TestFailed(
|
||||||
|
"While sending with <<%s>> bad data "
|
||||||
|
"<<%r>> (%d) received; "
|
||||||
|
"expected <<%r>> (%d)\n" % (
|
||||||
|
meth_name, outdata[:20], len(outdata),
|
||||||
|
indata[:20], len(indata)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except ValueError as e:
|
||||||
|
if expect_success:
|
||||||
|
raise support.TestFailed(
|
||||||
|
"Failed to send with method <<%s>>; "
|
||||||
|
"expected to succeed.\n" % (meth_name,)
|
||||||
|
)
|
||||||
|
if not str(e).startswith(meth_name):
|
||||||
|
raise support.TestFailed(
|
||||||
|
"Method <<%s>> failed with unexpected "
|
||||||
|
"exception message: %s\n" % (
|
||||||
|
meth_name, e
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for meth_name, recv_meth, expect_success, args in recv_methods:
|
||||||
|
indata = data_prefix + meth_name
|
||||||
|
try:
|
||||||
|
s.send(indata.encode('ASCII', 'strict'))
|
||||||
|
outdata = recv_meth(*args)
|
||||||
|
outdata = outdata.decode('ASCII', 'strict')
|
||||||
|
if outdata != indata.lower():
|
||||||
|
raise support.TestFailed(
|
||||||
|
"While receiving with <<%s>> bad data "
|
||||||
|
"<<%r>> (%d) received; "
|
||||||
|
"expected <<%r>> (%d)\n" % (
|
||||||
|
meth_name, outdata[:20], len(outdata),
|
||||||
|
indata[:20], len(indata)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except ValueError as e:
|
||||||
|
if expect_success:
|
||||||
|
raise support.TestFailed(
|
||||||
|
"Failed to receive with method <<%s>>; "
|
||||||
|
"expected to succeed.\n" % (meth_name,)
|
||||||
|
)
|
||||||
|
if not str(e).startswith(meth_name):
|
||||||
|
raise support.TestFailed(
|
||||||
|
"Method <<%s>> failed with unexpected "
|
||||||
|
"exception message: %s\n" % (
|
||||||
|
meth_name, e
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# consume data
|
||||||
|
s.read()
|
||||||
|
|
||||||
|
s.write("over\n".encode("ASCII", "strict"))
|
||||||
|
s.close()
|
||||||
|
finally:
|
||||||
|
server.stop()
|
||||||
|
server.join()
|
||||||
|
|
||||||
|
|
||||||
def test_main(verbose=False):
|
def test_main(verbose=False):
|
||||||
if skip_expected:
|
if skip_expected:
|
||||||
raise test_support.TestSkipped("No SSL support")
|
raise test_support.TestSkipped("No SSL support")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue