def do_handshake(self):
while True:
try:
self._sock.do_handshake()
break
except SSL.WantReadError:
sys.exc_clear()
wait_read(self.fileno())
except SSL.WantWriteError:
sys.exc_clear()
wait_write(self.fileno())
except SSL.SysCallError, ex:
raise sslerror(SysCallError_code_mapping.get(ex.args[0], ex.args[0]), ex.args[1])
except SSL.Error, ex:
raise sslerror(str(ex))
python类WantReadError()的实例源码
def load_crt(self, crt):
'''
Load certificate file content to openssl x509 object.
:param crt: Certificate file path.
:type crt: String.
:returns: Informational result dict {'error': Boolean, 'message': if error String else x509 object}
:rtype: Dict.
'''
try:
x509obj = crypto.load_certificate(
crypto.FILETYPE_PEM, open(crt).read())
except SSL.SysCallError as e:
res = {"error": True, "message": e.strerror + " " + e.filename}
#print(ex.args, ex.errno, ex.filename, ex.strerror)
except SSL.Error as f:
res = {"error": True, "message": f.strerror + " " + f.filename}
except SSL.WantReadError as r:
res = {"error": True, "message": r.strerror + " " + r.filename}
except SSL.WantWriteError as w:
res = {"error": True, "message": w.strerror + " " + w.filename}
except SSL.WantX509LookupError as x:
res = {"error": True, "message": x.strerror + " " + x.filename}
except Exception as ex:
res = {"error": True, "message": ex.strerror + " " + ex.filename}
except:
res = {"error": True, "message": "Unexpected error"}
else:
res = {"error": False, "message": x509obj}
finally:
return(res)
def go():
port = socket()
port.bind(('', 0))
port.listen(1)
called = []
def info(conn, where, ret):
print count.next()
called.append(None)
context = Context(TLSv1_METHOD)
context.set_info_callback(info)
context.use_certificate(
load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
context.use_privatekey(
load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
while 1:
client = socket()
client.setblocking(False)
client.connect_ex(port.getsockname())
clientSSL = Connection(Context(TLSv1_METHOD), client)
clientSSL.set_connect_state()
server, ignored = port.accept()
server.setblocking(False)
serverSSL = Connection(context, server)
serverSSL.set_accept_state()
del called[:]
while not called:
for ssl in clientSSL, serverSSL:
try:
ssl.do_handshake()
except WantReadError:
pass
def go():
port = socket()
port.bind(('', 0))
port.listen(1)
called = []
def info(*args):
print count.next()
called.append(None)
return 1
context = Context(TLSv1_METHOD)
context.set_verify(VERIFY_PEER, info)
context.use_certificate(
load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
context.use_privatekey(
load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
while 1:
client = socket()
client.setblocking(False)
client.connect_ex(port.getsockname())
clientSSL = Connection(context, client)
clientSSL.set_connect_state()
server, ignored = port.accept()
server.setblocking(False)
serverSSL = Connection(context, server)
serverSSL.set_accept_state()
del called[:]
while not called:
for ssl in clientSSL, serverSSL:
try:
ssl.send('foo')
except WantReadError, e:
pass
def read_from_fd(self):
if self._ssl_accepting:
return None
try:
chunk = self.socket.read(self.read_chunk_size)
except SSL.WantReadError:
return None
except SSL.ZeroReturnError:
self.close(exc_info=True)
return None
except SSL.SysCallError as e:
err_num = abs(e[0])
if err_num in (errno.EWOULDBLOCK, errno.EAGAIN):
return None
# NOTE: We will handle the self.close in here.
# _read_to_buffer of BaseIOStream will not chceck SSL.SysCallError
if err_num == errno.EPERM:
self.close(exc_info=True)
return None
self.close(exc_info=True)
raise
# NOTE: Just in case we missed some SSL Error type.
except SSL.Error as e:
raise
if not chunk:
self.close()
return None
return chunk
def _start_tls_handshake(self, response, **kwargs):
"""
[MS-CSSP] v13.0 2016-07-14
3.1.5 Processing Events and Sequencing Rules - Step 1
This is the first step in a CredSSP auth sequence where the client and server complete the TLS handshake as
specified in RFC2246. After the handshake is complete, all subsequent CredSSP Protocol messages are encrypted
by the TLS channel.
:param response: The original 401 response from the server
:param kwargs: The requests kwargs from the original response
"""
# Check that the server support CredSSP authentication
self._check_credssp_supported(response)
self.tls_connection = SSL.Connection(self.tls_context)
self.tls_connection.set_connect_state()
log.debug("_start_tls_handshake(): Starting TLS handshake with server")
while True:
try:
self.tls_connection.do_handshake()
except SSL.WantReadError:
request = response.request.copy()
credssp_token = self.tls_connection.bio_read(self.BIO_BUFFER_SIZE)
self._set_credssp_token(request, credssp_token)
response = response.connection.send(request, **kwargs)
response.content
response.raw.release_conn()
server_credssp_token = self._get_credssp_token(response)
self.tls_connection.bio_write(server_credssp_token)
else:
break
self.cipher_negotiated = self.tls_connection.get_cipher_name()
log.debug("_start_tls_handshake(): Handshake complete. Protocol: %s, Cipher: %s" % (
self.tls_connection.get_protocol_version_name(), self.tls_connection.get_cipher_name()))
def wrap(self, data):
"""
Encrypts the data in preparation for sending to the server. The data is
encrypted using the TLS channel negotiated between the client and the
server.
:param data: a byte string of data to encrypt
:return: a byte string of the encrypted data
"""
length = self.tls_connection.send(data)
encrypted_data = b''
counter = 0
while True:
try:
encrypted_chunk = self.tls_connection.bio_read(self.BIO_BUFFER_SIZE)
except SSL.WantReadError:
break
encrypted_data += encrypted_chunk
# in case of a borked TLS connection, break the loop if the current
# buffer counter is > the length of the original message plus the
# the size of the buffer (to be careful)
counter += self.BIO_BUFFER_SIZE
if counter > length + self.BIO_BUFFER_SIZE:
break
return encrypted_data
def init_connection(self):
self.connect()
#This is copied from tds.py
resp = self.preLogin()
if resp['Encryption'] == TDS_ENCRYPT_REQ or resp['Encryption'] == TDS_ENCRYPT_OFF:
logging.info("Encryption required, switching to TLS")
# Switching to TLS now
ctx = SSL.Context(SSL.TLSv1_METHOD)
ctx.set_cipher_list('RC4')
tls = SSL.Connection(ctx,None)
tls.set_connect_state()
while True:
try:
tls.do_handshake()
except SSL.WantReadError:
data = tls.bio_read(4096)
self.sendTDS(TDS_PRE_LOGIN, data,0)
tds = self.recvTDS()
tls.bio_write(tds['Data'])
else:
break
# SSL and TLS limitation: Secure Socket Layer (SSL) and its replacement,
# Transport Layer Security(TLS), limit data fragments to 16k in size.
self.packetSize = 16*1024-1
self.tlsSocket = tls
self.resp = resp
def test_set_info_callback(self):
"""
L{Context.set_info_callback} accepts a callable which will be invoked
when certain information about an SSL connection is available.
"""
(server, client) = socket_pair()
clientSSL = Connection(Context(TLSv1_METHOD), client)
clientSSL.set_connect_state()
called = []
def info(conn, where, ret):
called.append((conn, where, ret))
context = Context(TLSv1_METHOD)
context.set_info_callback(info)
context.use_certificate(
load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
context.use_privatekey(
load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
serverSSL = Connection(context, server)
serverSSL.set_accept_state()
while not called:
for ssl in clientSSL, serverSSL:
try:
ssl.do_handshake()
except WantReadError:
pass
# Kind of lame. Just make sure it got called somehow.
self.assertTrue(called)
def _load_verify_locations_test(self, *args):
(server, client) = socket_pair()
clientContext = Context(TLSv1_METHOD)
clientContext.load_verify_locations(*args)
# Require that the server certificate verify properly or the
# connection will fail.
clientContext.set_verify(
VERIFY_PEER,
lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
clientSSL = Connection(clientContext, client)
clientSSL.set_connect_state()
serverContext = Context(TLSv1_METHOD)
serverContext.use_certificate(
load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
serverContext.use_privatekey(
load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
serverSSL = Connection(serverContext, server)
serverSSL.set_accept_state()
for i in range(3):
for ssl in clientSSL, serverSSL:
try:
# Without load_verify_locations above, the handshake
# will fail:
# Error: [('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE',
# 'certificate verify failed')]
ssl.do_handshake()
except WantReadError:
pass
cert = clientSSL.get_peer_certificate()
self.assertEqual(cert.get_subject().CN, 'Testing Root CA')
def test_socketConnect(self):
"""
Just like L{test_memoryConnect} but with an actual socket.
This is primarily to rule out the memory BIO code as the source of
any problems encountered while passing data over a L{Connection} (if
this test fails, there must be a problem outside the memory BIO
code, as no memory BIO is involved here). Even though this isn't a
memory BIO test, it's convenient to have it here.
"""
(server, client) = socket_pair()
# Let the encryption begin...
client_conn = self._client(client)
server_conn = self._server(server)
# Establish the connection
established = False
while not established:
established = True # assume the best
for ssl in client_conn, server_conn:
try:
# Generally a recv() or send() could also work instead
# of do_handshake(), and we would stop on the first
# non-exception.
ssl.do_handshake()
except WantReadError:
established = False
important_message = "Help me Obi Wan Kenobi, you're my only hope."
client_conn.send(important_message)
msg = server_conn.recv(1024)
self.assertEqual(msg, important_message)
# Again in the other direction, just for fun.
important_message = important_message[::-1]
server_conn.send(important_message)
msg = client_conn.recv(1024)
self.assertEqual(msg, important_message)
def test_shutdown(self):
"""
L{Connection.bio_shutdown} signals the end of the data stream from
which the L{Connection} reads.
"""
server = self._server(None)
server.bio_shutdown()
e = self.assertRaises(Error, server.recv, 1024)
# We don't want WantReadError or ZeroReturnError or anything - it's a
# handshake failure.
self.assertEquals(e.__class__, Error)
def _send_raw(self):
while True:
self.ssl_write = None
slen = 0
try:
slen = self.sock.send(self.send_buf)
except (socket.error, OSError, SSL.ZeroReturnError, SSL.SysCallError, SSL.WantReadError):
break
except SSL.WantWriteError:
self.ssl_write = True
self.send_buf = self.send_buf[slen:]
if len(self.send_buf) < 1:
self.send_buf = None
break
def do_handshake(self):
while True:
try:
self._sock.do_handshake()
break
except SSL.WantReadError:
sys.exc_clear()
wait_read(self.fileno())
except SSL.WantWriteError:
sys.exc_clear()
wait_write(self.fileno())
except SSL.SysCallError, ex:
raise sslerror(SysCallError_code_mapping.get(ex.args[0], ex.args[0]), ex.args[1])
except SSL.Error, ex:
raise sslerror(str(ex))
def _flushSendBIO(self):
"""
Read any bytes out of the send BIO and write them to the underlying
transport.
"""
try:
bytes = self._tlsConnection.bio_read(2 ** 15)
except WantReadError:
# There may be nothing in the send BIO right now.
pass
else:
self.transport.write(bytes)
def _flushReceiveBIO(self):
"""
Try to receive any application-level bytes which are now available
because of a previous write into the receive BIO. This will take
care of delivering any application-level bytes which are received to
the protocol, as well as handling of the various exceptions which
can come from trying to get such bytes.
"""
# Keep trying this until an error indicates we should stop or we
# close the connection. Looping is necessary to make sure we
# process all of the data which was put into the receive BIO, as
# there is no guarantee that a single recv call will do it all.
while not self._lostTLSConnection:
try:
bytes = self._tlsConnection.recv(2 ** 15)
except WantReadError:
# The newly received bytes might not have been enough to produce
# any application data.
break
except ZeroReturnError:
# TLS has shut down and no more TLS data will be received over
# this connection.
self._shutdownTLS()
# Passing in None means the user protocol's connnectionLost
# will get called with reason from underlying transport:
self._tlsShutdownFinished(None)
except Error:
# Something went pretty wrong. For example, this might be a
# handshake failure during renegotiation (because there were no
# shared ciphers, because a certificate failed to verify, etc).
# TLS can no longer proceed.
failure = Failure()
self._tlsShutdownFinished(failure)
else:
if not self._aborted:
ProtocolWrapper.dataReceived(self, bytes)
# The received bytes might have generated a response which needs to be
# sent now. For example, the handshake involves several round-trip
# exchanges without ever producing application-bytes.
self._flushSendBIO()
def _write(self, bytes):
"""
Process the given application bytes and send any resulting TLS traffic
which arrives in the send BIO.
This may be called by C{dataReceived} with bytes that were buffered
before C{loseConnection} was called, which is why this function
doesn't check for disconnection but accepts the bytes regardless.
"""
if self._lostTLSConnection:
return
# A TLS payload is 16kB max
bufferSize = 2 ** 14
# How far into the input we've gotten so far
alreadySent = 0
while alreadySent < len(bytes):
toSend = bytes[alreadySent:alreadySent + bufferSize]
try:
sent = self._tlsConnection.send(toSend)
except WantReadError:
self._bufferedWrite(bytes[alreadySent:])
break
except Error:
# Pretend TLS connection disconnected, which will trigger
# disconnect of underlying transport. The error will be passed
# to the application protocol's connectionLost method. The
# other SSL implementation doesn't, but losing helpful
# debugging information is a bad idea.
self._tlsShutdownFinished(Failure())
break
else:
# We've successfully handed off the bytes to the OpenSSL
# Connection object.
alreadySent += sent
# See if OpenSSL wants to hand any bytes off to the underlying
# transport as a result.
self._flushSendBIO()
def do_handshake(self):
while True:
try:
self._sock.do_handshake()
break
except SSL.WantReadError:
sys.exc_clear()
wait_read(self.fileno())
except SSL.WantWriteError:
sys.exc_clear()
wait_write(self.fileno())
except SSL.SysCallError, ex:
raise sslerror(SysCallError_code_mapping.get(ex.args[0], ex.args[0]), ex.args[1])
except SSL.Error, ex:
raise sslerror(str(ex))
def __iowait(self, io_func, *args, **kwargs):
timeout = self._sock.gettimeout()
fd = self._sock
while self._connection:
try:
return io_func(*args, **kwargs)
except (SSL.WantReadError, SSL.WantX509LookupError):
#exc_clear()
rd, _, ed = select([fd], [], [fd], timeout)
if ed:
raise socket.error(ed)
if not rd:
raise socket.timeout('The read operation timed out')
except SSL.WantWriteError:
#exc_clear()
_, wd, ed = select([], [fd], [fd], timeout)
if ed:
raise socket.error(ed)
if not wd:
raise socket.timeout('The write operation timed out')
except SSL.SysCallError as e:
if e.args[0] == errno.EWOULDBLOCK:
#exc_clear()
rd, wd, ed = select([fd], [fd], [fd], timeout)
if ed:
raise socket.error(ed)
if not rd and not wd:
raise socket.timeout('The socket operation timed out')
elif e.args[0] == errno.EAGAIN:
continue
else:
raise e
def _loopback(self, client_conn, server_conn):
"""
Try to read application bytes from each of the two L{Connection}
objects. Copy bytes back and forth between their send/receive buffers
for as long as there is anything to copy. When there is nothing more
to copy, return C{None}. If one of them actually manages to deliver
some application bytes, return a two-tuple of the connection from which
the bytes were read and the bytes themselves.
"""
wrote = True
while wrote:
# Loop until neither side has anything to say
wrote = False
# Copy stuff from each side's send buffer to the other side's
# receive buffer.
for (read, write) in [(client_conn, server_conn),
(server_conn, client_conn)]:
# Give the side a chance to generate some more bytes, or
# succeed.
try:
bytes = read.recv(2 ** 16)
except WantReadError:
# It didn't succeed, so we'll hope it generated some
# output.
pass
else:
# It did succeed, so we'll stop now and let the caller deal
# with it.
return (read, bytes)
while True:
# Keep copying as long as there's more stuff there.
try:
dirty = read.bio_read(4096)
except WantReadError:
# Okay, nothing more waiting to be sent. Stop
# processing this send buffer.
break
else:
# Keep track of the fact that someone generated some
# output.
wrote = True
write.bio_write(dirty)