def upgradetotls(self):
"""
upgrade to a tls wrapped connection
:return: None
"""
# TODO: newer TLS version?
# noinspection PyUnresolvedReferences
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
# TODO: PLATFORM STAGECERTIFICATEFILE is not the correct name for this value, move to handler or set a different
# variable in TRANSPORT with the same initial value?
certkeyfile = sanatizefilename(self.handler.platform.options['STAGECERTIFICATEFILE']['Value'])
context.load_cert_chain(certfile=certkeyfile, keyfile=certkeyfile)
self.conn = context.wrap_bio(self.recvdataqueue.memorybio, self.senddataqueue.memorybio, server_side=True)
print_message("Waiting for connection and TLS handshake...")
while True:
try:
self.conn.do_handshake()
break
except (ssl.SSLWantReadError, ssl.SSLSyscallError):
pass
print_message("Upgrade to TLS done")
python类SSLWantReadError()的实例源码
def _do_ssl_handshake(self):
incoming = ssl.MemoryBIO()
outgoing = ssl.MemoryBIO()
sslobj = ssl.SSLContext().wrap_bio(incoming, outgoing, False)
# do_handshake()
while True:
try:
sslobj.do_handshake()
except ssl.SSLWantReadError:
self._send_message(TDS_PRELOGIN, outgoing.read())
tag, _, _, buf = self._read_response_packet()
assert tag == TDS_PRELOGIN
incoming.write(buf)
else:
break
return sslobj, incoming, outgoing
def _read(self, ln):
if not self.sock:
raise OperationalError("Lost connection")
if self.sslobj:
while True:
try:
r = self.sslobj.read(ln)
except ssl.SSLWantReadError:
b = self.sock.recv(32768)
self.incoming.write(b)
continue
break
else:
r = b''
while len(r) < ln:
b = self.sock.recv(ln-len(r))
if not b:
raise OperationalError("Can't recv packets")
r += b
return r
def __read(self):
while 1:
try:
rdata = self.__socket.recv(4096)
except BlockingIOError:
break
except ssl.SSLWantReadError:
break
if self.__ssl_on and not self.__ssl_ok:
if self.__alpn_on:
protocol = self.__socket.selected_alpn_protocol()
if protocol == "h2": self.__is_http2 = True
self.__ssl_ok = True
if rdata:
# if not self.__fd: self.__fd = open("test.txt", "wb")
# self.__fd.write(rdata)
self.__reader._putvalue(rdata)
else:
raise HttpErr("the connection has been closed")
return
def _do_tls_handshake(self):
logging.debug('Initializing TLS connection with {}:{}'.format(self.host, self.port))
self.s = ssl.wrap_socket(self.s, keyfile=os.path.join(shared.source_directory, 'tls', 'key.pem'),
certfile=os.path.join(shared.source_directory, 'tls', 'cert.pem'),
server_side=self.server, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False,
ciphers='AECDH-AES256-SHA', suppress_ragged_eofs=True)
if hasattr(self.s, "context"):
self.s.context.set_ecdh_curve("secp256k1")
while True:
try:
self.s.do_handshake()
break
except ssl.SSLWantReadError:
select.select([self.s], [], [])
except ssl.SSLWantWriteError:
select.select([], [self.s], [])
except Exception as e:
logging.debug('Disconnecting from {}:{}. Reason: {}'.format(self.host, self.port, e))
self.status = 'disconnecting'
break
self.tls = True
logging.debug('Established TLS connection with {}:{}'.format(self.host, self.port))
def handle_in(self):
self._sync_tls_in()
try:
data = self.tls.read()
except ssl.SSLWantReadError:
return
if data.startswith(b'\x00\x00\x00\x00'):
self.read_control_message(data)
elif data.startswith(b'PUSH_REPLY'):
self.c.on_push(data)
elif data.startswith(b'AUTH_FAILED'):
raise AuthFailed()
else:
self.log.warn("Unknown control packet: %r", data)
def recv_blocked(self, buflen=8*1024, timeout=None, *args, **kwargs):
force_first_loop_iteration = True
end = time.time()+timeout if timeout else 0
while force_first_loop_iteration or (not timeout or time.time()<end):
# force one recv otherwise we might not even try to read if timeout is too narrow
try:
return self.recv(buflen=buflen, *args, **kwargs)
except ssl.SSLWantReadError:
pass
force_first_loop_iteration = False
def receive(self, leng=1024):
"""
receive data from connected host
:param leng: length of data to collect
:return: data
"""
if not self.server:
print_error("Connection not open")
return
data = None
# if wrapped by a TLS connection, read from there
if self.conn:
while data is None:
# if there is no data in either queue, block until there is
while self.conn.pending() <= 0 and not self.recvdataqueue.has_data():
time.sleep(0.1)
print_debug(DEBUG_MODULE, "conn.pending = {}, recvdataqueue = {}"
.format(self.conn.pending(), self.recvdataqueue.length()))
try:
data = self.conn.read(leng)
break
except (ssl.SSLWantReadError, ssl.SSLSyscallError):
pass
# else, read from the dataqueue normally
else:
# if there is no data, block until there is
while not self.recvdataqueue.has_data():
pass
data = self.recvdataqueue.read(leng)
# finish even if less data than requested, higher level must handle this
return data
def _read_ready(self):
if self._write_wants_read:
self._write_wants_read = False
self._write_ready()
if self._buffer:
self._loop.add_writer(self._sock_fd, self._write_ready)
try:
data = self._sock.recv(self.max_size)
except (BlockingIOError, InterruptedError, ssl.SSLWantReadError):
pass
except ssl.SSLWantWriteError:
self._read_wants_write = True
self._loop.remove_reader(self._sock_fd)
self._loop.add_writer(self._sock_fd, self._write_ready)
except Exception as exc:
self._fatal_error(exc, 'Fatal read error on SSL transport')
else:
if data:
self._protocol.data_received(data)
else:
try:
if self._loop.get_debug():
logger.debug("%r received EOF", self)
keep_open = self._protocol.eof_received()
if keep_open:
logger.warning('returning true from eof_received() '
'has no effect when using ssl')
finally:
self.close()
def _write_ready(self):
if self._read_wants_write:
self._read_wants_write = False
self._read_ready()
if not (self._paused or self._closing):
self._loop.add_reader(self._sock_fd, self._read_ready)
if self._buffer:
try:
n = self._sock.send(self._buffer)
except (BlockingIOError, InterruptedError, ssl.SSLWantWriteError):
n = 0
except ssl.SSLWantReadError:
n = 0
self._loop.remove_writer(self._sock_fd)
self._write_wants_read = True
except Exception as exc:
self._loop.remove_writer(self._sock_fd)
self._buffer.clear()
self._fatal_error(exc, 'Fatal write error on SSL transport')
return
if n:
del self._buffer[:n]
self._maybe_resume_protocol() # May append to buffer.
if not self._buffer:
self._loop.remove_writer(self._sock_fd)
if self._closing:
self._call_connection_lost(None)
def test_on_handshake_reader_retry(self):
self.loop.set_debug(False)
self.sslsock.do_handshake.side_effect = ssl.SSLWantReadError
transport = self.ssl_transport()
self.loop.assert_reader(1, transport._on_handshake, None)
def test_read_ready_recv_retry(self):
self.sslsock.recv.side_effect = ssl.SSLWantReadError
transport = self._make_one()
transport._read_ready()
self.assertTrue(self.sslsock.recv.called)
self.assertFalse(self.protocol.data_received.called)
self.sslsock.recv.side_effect = BlockingIOError
transport._read_ready()
self.assertFalse(self.protocol.data_received.called)
self.sslsock.recv.side_effect = InterruptedError
transport._read_ready()
self.assertFalse(self.protocol.data_received.called)
def test_close_not_connected(self):
self.sslsock.do_handshake.side_effect = ssl.SSLWantReadError
self.check_close()
self.assertFalse(self.protocol.connection_made.called)
self.assertFalse(self.protocol.connection_lost.called)
def _retry(self, fn, *args):
finished = False
while not finished:
want_read = False
try:
ret = fn(*args)
except ssl.SSLWantReadError:
want_read = True
except ssl.SSLWantWriteError:
# can't happen, but if it did this would be the right way to
# handle it anyway
pass
else:
finished = True
# do any sending
data = self.outgoing.read()
if data:
self.sock.sendall(data)
# do any receiving
if want_read:
data = self.sock.recv(BUFSIZE)
if not data:
self.incoming.write_eof()
else:
self.incoming.write(data)
# then retry if necessary
return ret
def _handshake(self):
try:
self.socket.do_handshake(block=True)
except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
pass
def handle_read(self):
while True:
try:
asynchat.async_chat.handle_read(self)
except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
self._handshake()
else:
break
def handle_error(self):
# Just ignore ssl read errors, they don't seem to matter
if sys.exc_info()[0] == ssl.SSLWantReadError:
return
if not self.reconnecting:
log.error('Unknown error occurred.', exc_info=True)
self.reconnect_with_delay()
def connect(self, server):
"""Creates a (ssl) socket and connects to the server. Not using asyncore's connect-function because it sucks."""
# sockets are garbage collected, but if the connection isn't closed it might fail
try:
self.socket.shutdown(socket.SHUT_WR)
self.socket.close()
del self.socket
except Exception:
pass
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
if self.use_ssl:
try:
self.socket.setblocking(True)
self.socket = ssl.wrap_socket(self.socket)
except (ssl.SSLWantReadError, ssl.SSLWantWriteError) as e:
log.debug(e)
self._handshake()
except ssl.SSLError as e:
log.error(e)
self.exit()
return
finally:
self.socket.setblocking(False)
log.info('Connecting to %s', self.current_server)
self.socket.settimeout(30)
self.socket.connect(server)
self.handle_connect_event()
def _read_ready(self):
if self._conn_lost:
return
if self._write_wants_read:
self._write_wants_read = False
self._write_ready()
if self._buffer:
self._loop._add_writer(self._sock_fd, self._write_ready)
try:
data = self._sock.recv(self.max_size)
except (BlockingIOError, InterruptedError, ssl.SSLWantReadError):
pass
except ssl.SSLWantWriteError:
self._read_wants_write = True
self._loop._remove_reader(self._sock_fd)
self._loop._add_writer(self._sock_fd, self._write_ready)
except Exception as exc:
self._fatal_error(exc, 'Fatal read error on SSL transport')
else:
if data:
self._protocol.data_received(data)
else:
try:
if self._loop.get_debug():
logger.debug("%r received EOF", self)
keep_open = self._protocol.eof_received()
if keep_open:
logger.warning('returning true from eof_received() '
'has no effect when using ssl')
finally:
self.close()
def _write_ready(self):
if self._conn_lost:
return
if self._read_wants_write:
self._read_wants_write = False
self._read_ready()
if not (self._paused or self._closing):
self._loop._add_reader(self._sock_fd, self._read_ready)
if self._buffer:
try:
n = self._sock.send(self._buffer)
except (BlockingIOError, InterruptedError, ssl.SSLWantWriteError):
n = 0
except ssl.SSLWantReadError:
n = 0
self._loop._remove_writer(self._sock_fd)
self._write_wants_read = True
except Exception as exc:
self._loop._remove_writer(self._sock_fd)
self._buffer.clear()
self._fatal_error(exc, 'Fatal write error on SSL transport')
return
if n:
del self._buffer[:n]
self._maybe_resume_protocol() # May append to buffer.
if not self._buffer:
self._loop._remove_writer(self._sock_fd)
if self._closing:
self._call_connection_lost(None)
def do_handshake(self):
try:
super(SSLSocket, self).do_handshake()
except ssl.SSLWantReadError:
return 1
except ssl.SSLWantWriteError:
return 2
return self._do_flux_handshake()
def do_handshake(self):
# incoming <- ClientHello
client_hello_size = struct.unpack('>I', recvall(self.socket, 4))[0]
client_hello = recvall(self.socket, client_hello_size)
self.incoming.write(client_hello)
# ServerHello..ServerHelloDone -> outgoing
try:
self.tls_bio.do_handshake()
except ssl.SSLWantReadError:
server_hello = self.outgoing.read()
server_hello_size = struct.pack('>I', len(server_hello))
self.socket.sendall(server_hello_size)
self.socket.sendall(server_hello)
# incoming <- [client]Certificate*..ClientKeyExchange..Finished
client_keyexchange_size = struct.unpack('>I', recvall(self.socket, 4))[0]
client_keyexchange = recvall(self.socket, client_keyexchange_size)
self.incoming.write(client_keyexchange)
# ChangeCipherSpec..Finished -> outgoing
self.tls_bio.do_handshake()
server_change_cipher_spec = self.outgoing.read()
server_change_cipher_spec_size = struct.pack('>I', len(server_change_cipher_spec))
self.socket.sendall(server_change_cipher_spec_size)
self.socket.sendall(server_change_cipher_spec)
def _read_ready(self):
if self._write_wants_read:
self._write_wants_read = False
self._write_ready()
if self._buffer:
self._loop.add_writer(self._sock_fd, self._write_ready)
try:
data = self._sock.recv(self.max_size)
except (BlockingIOError, InterruptedError, ssl.SSLWantReadError):
pass
except ssl.SSLWantWriteError:
self._read_wants_write = True
self._loop.remove_reader(self._sock_fd)
self._loop.add_writer(self._sock_fd, self._write_ready)
except Exception as exc:
self._fatal_error(exc, 'Fatal read error on SSL transport')
else:
if data:
self._protocol.data_received(data)
else:
try:
if self._loop.get_debug():
logger.debug("%r received EOF", self)
keep_open = self._protocol.eof_received()
if keep_open:
logger.warning('returning true from eof_received() '
'has no effect when using ssl')
finally:
self.close()
def _write_ready(self):
if self._read_wants_write:
self._read_wants_write = False
self._read_ready()
if not (self._paused or self._closing):
self._loop.add_reader(self._sock_fd, self._read_ready)
if self._buffer:
try:
n = self._sock.send(self._buffer)
except (BlockingIOError, InterruptedError, ssl.SSLWantWriteError):
n = 0
except ssl.SSLWantReadError:
n = 0
self._loop.remove_writer(self._sock_fd)
self._write_wants_read = True
except Exception as exc:
self._loop.remove_writer(self._sock_fd)
self._buffer.clear()
self._fatal_error(exc, 'Fatal write error on SSL transport')
return
if n:
del self._buffer[:n]
self._maybe_resume_protocol() # May append to buffer.
if not self._buffer:
self._loop.remove_writer(self._sock_fd)
if self._closing:
self._call_connection_lost(None)
def test_on_handshake_reader_retry(self):
self.loop.set_debug(False)
self.sslsock.do_handshake.side_effect = ssl.SSLWantReadError
transport = self.ssl_transport()
self.loop.assert_reader(1, transport._on_handshake, None)
def test_read_ready_recv_retry(self):
self.sslsock.recv.side_effect = ssl.SSLWantReadError
transport = self._make_one()
transport._read_ready()
self.assertTrue(self.sslsock.recv.called)
self.assertFalse(self.protocol.data_received.called)
self.sslsock.recv.side_effect = BlockingIOError
transport._read_ready()
self.assertFalse(self.protocol.data_received.called)
self.sslsock.recv.side_effect = InterruptedError
transport._read_ready()
self.assertFalse(self.protocol.data_received.called)
def test_write_ready_send_read(self):
transport = self._make_one()
transport._buffer = list_to_buffer([b'data'])
self.loop.remove_writer = mock.Mock()
self.sslsock.send.side_effect = ssl.SSLWantReadError
transport._write_ready()
self.assertFalse(self.protocol.data_received.called)
self.assertTrue(transport._write_wants_read)
self.loop.remove_writer.assert_called_with(transport._sock_fd)
def _try_handshake(self):
assert self.config['security_protocol'] in ('SSL', 'SASL_SSL')
try:
self._sock.do_handshake()
return True
# old ssl in python2.6 will swallow all SSLErrors here...
except (SSLWantReadError, SSLWantWriteError):
pass
except (SSLZeroReturnError, ConnectionError):
log.warning('SSL connection closed by server during handshake.')
self.close(Errors.ConnectionError('SSL connection closed by server during handshake'))
# Other SSLErrors will be raised to user
return False
def try_handshake(self):
try:
self.tls.do_handshake()
return True
except ssl.SSLWantReadError:
pass
self._sync_tls_out()
self._sync_tls_in()
return False
def _read_ready(self):
if self._write_wants_read:
self._write_wants_read = False
self._write_ready()
if self._buffer:
self._loop.add_writer(self._sock_fd, self._write_ready)
try:
data = self._sock.recv(self.max_size)
except (BlockingIOError, InterruptedError, ssl.SSLWantReadError):
pass
except ssl.SSLWantWriteError:
self._read_wants_write = True
self._loop.remove_reader(self._sock_fd)
self._loop.add_writer(self._sock_fd, self._write_ready)
except Exception as exc:
self._fatal_error(exc, 'Fatal read error on SSL transport')
else:
if data:
self._protocol.data_received(data)
else:
try:
if self._loop.get_debug():
logger.debug("%r received EOF", self)
keep_open = self._protocol.eof_received()
if keep_open:
logger.warning('returning true from eof_received() '
'has no effect when using ssl')
finally:
self.close()