PyBitmessage/src/network/tls.py

120 lines
4.6 KiB
Python
Raw Normal View History

"""
SSL/TLS negotiation.
"""
2017-04-16 18:27:15 +02:00
import os
import socket
import ssl
import sys
2017-04-16 18:27:15 +02:00
from network.advanceddispatcher import AdvancedDispatcher
import network.asyncore_pollchoose as asyncore
import paths
import protocol
2017-04-04 10:46:01 +02:00
class TLSDispatcher(AdvancedDispatcher):
def __init__(self, address=None, sock=None,
2017-04-04 10:46:01 +02:00
certfile=None, keyfile=None, server_side=False, ciphers=protocol.sslProtocolCiphers):
self.want_read = self.want_write = True
2017-04-04 10:46:01 +02:00
if certfile is None:
self.certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem')
else:
self.certfile = certfile
if keyfile is None:
self.keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem')
else:
self.keyfile = keyfile
self.server_side = server_side
self.ciphers = ciphers
2017-04-04 10:46:01 +02:00
self.tlsStarted = False
self.tlsDone = False
2017-04-04 10:46:01 +02:00
self.isSSL = False
2017-04-04 10:46:01 +02:00
def state_tls_init(self):
self.isSSL = True
2017-04-16 18:27:15 +02:00
self.tlsStarted = True
# Once the connection has been established, it's safe to wrap the
# socket.
if sys.version_info >= (2,7,9):
context = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH if self.server_side else ssl.Purpose.CLIENT_AUTH)
context.set_ciphers(self.ciphers)
2017-04-04 10:46:01 +02:00
context.set_ecdh_curve("secp256k1")
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
# also exclude TLSv1 and TLSv1.1 in the future
2017-04-04 10:46:01 +02:00
context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE
2017-04-16 18:27:15 +02:00
self.sslSocket = context.wrap_socket(self.socket, server_side = self.server_side, do_handshake_on_connect=False)
else:
self.sslSocket = ssl.wrap_socket(self.socket,
server_side=self.server_side,
ssl_version=protocol.sslProtocolVersion,
certfile=self.certfile,
keyfile=self.keyfile,
ciphers=self.ciphers,
do_handshake_on_connect=False)
self.sslSocket.setblocking(0)
self.want_read = self.want_write = True
2017-04-16 18:27:15 +02:00
self.set_state("tls_handshake")
# if hasattr(self.socket, "context"):
# self.socket.context.set_ecdh_curve("secp256k1")
def writable(self):
2017-04-16 18:27:15 +02:00
if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0:
print "tls writable, %r" % (self.want_write)
2017-04-04 10:46:01 +02:00
return self.want_write
else:
2017-04-16 18:27:15 +02:00
return AdvancedDispatcher.writable(self)
def readable(self):
2017-04-16 18:27:15 +02:00
if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0:
print "tls readable, %r" % (self.want_read)
2017-04-04 10:46:01 +02:00
return self.want_read
else:
2017-04-16 18:27:15 +02:00
return AdvancedDispatcher.readable(self)
def handle_read(self):
2017-04-16 18:27:15 +02:00
# wait for write buffer flush
if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0:
print "handshaking (read)"
self.state_tls_handshake()
2017-04-04 10:46:01 +02:00
else:
2017-04-16 18:27:15 +02:00
print "not handshaking (read)"
return AdvancedDispatcher.handle_read(self)
def handle_write(self):
2017-04-16 18:27:15 +02:00
# wait for write buffer flush
if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0:
print "handshaking (write)"
self.state_tls_handshake()
2017-04-04 10:46:01 +02:00
else:
2017-04-16 18:27:15 +02:00
print "not handshaking (write)"
return AdvancedDispatcher.handle_write(self)
2017-04-04 10:46:01 +02:00
def state_tls_handshake(self):
2017-04-16 18:27:15 +02:00
# wait for flush
if len(self.write_buf) > 0:
return False
# Perform the handshake.
try:
2017-04-16 18:27:15 +02:00
print "handshaking (internal)"
self.sslSocket.do_handshake()
except ssl.SSLError, err:
2017-04-16 18:27:15 +02:00
print "handshake fail"
self.want_read = self.want_write = False
if err.args[0] == ssl.SSL_ERROR_WANT_READ:
2017-04-16 18:27:15 +02:00
print "want read"
self.want_read = True
elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
2017-04-16 18:27:15 +02:00
print "want write"
self.want_write = True
else:
raise
else:
2017-04-16 18:27:15 +02:00
print "handshake success"
# The handshake has completed, so remove this channel and...
self.del_channel()
self.set_socket(self.sslSocket)
self.tlsDone = True
2017-04-16 18:27:15 +02:00
self.state_bm_ready()
return False