Created
January 22, 2013 23:24
-
-
Save saghul/4599801 to your computer and use it in GitHub Desktop.
Revisions
-
saghul created this gist
Jan 22, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,12 @@ -----BEGIN CERTIFICATE----- MIIBrzCCARgCAQAwDQYJKoZIhvcNAQEEBQAwIDEeMBwGA1UEAxMVQ2VydGlmaWNh dGUgQXV0aG9yaXR5MB4XDTEzMDEyMjAwNTkzMVoXDTE4MDEyMTAwNTkzMVowIDEe MBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDK3qyBBmFrIE/1+sRndzKZYz1vjeA7uDGpyRIeKufl6MyKBPLu 9Irhmy9kveRcpaSouyXgMnYtFqmMdNqxmBukF15o0HXcEAfHavtZ4N62CxQgUy25 nW0pBB3Rohxjz7ugpYOr8sOu7zrc3VpTN733LlOh/RPNTbKFWBoy0XW/vQIDAQAB MA0GCSqGSIb3DQEBBAUAA4GBAH1ibeupY9p+KRKxEa9IYg4UUndxlnpr/xnxuy4o MJmSfLdvXZHsnV+93I/fbZIZHDJgd/VXBDUXF3wqdO9JHwk4g9VOO7LMIFZOqnpi 4ua8ctg+GCQiEdHUEQ/grWPgS7dW+FTDUXS8S44hskVpTmZOJFuJhTegsLYp0nfq X+FD -----END CERTIFICATE----- This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,11 @@ -----BEGIN CERTIFICATE----- MIIBpzCCARACAQEwDQYJKoZIhvcNAQEEBQAwIDEeMBwGA1UEAxMVQ2VydGlmaWNh dGUgQXV0aG9yaXR5MB4XDTEzMDEyMjAwNTkzMVoXDTE4MDEyMTAwNTkzMVowGDEW MBQGA1UEAxMNU2ltcGxlIENsaWVudDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC gYEAwci98l6/QjbU+9YB8NQSn0FEmj+C7slcEuSOFrb4zOGHHneZq8gH7VlwuQvj MzQHb+0v+wM3YObii3O0YXR6PAbqAvzdmpYgPlUqXJNiEBlvKT5BOZHr9jriy+EP 9yD6X+dv6nPSf6jtuFwgO+fs6ztRisf3VnyIns5ib10AvmECAwEAATANBgkqhkiG 9w0BAQQFAAOBgQA2S8HK9lSvdOSkyZ9zSHCi7ZNzb6ieT17YJwiWr4WCqJGmLm6t tdEQwbb+NRhr5WwMtkQoYJg8bv1vuF6BEMAVgZXvavVWaRUJmodDOwYmPAeRMLqF cG193wpchToWIvyPedB1Xq/vJI6LUVOvGAfUPmW2r++2bncBKAw493eBqw== -----END CERTIFICATE----- This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDByL3yXr9CNtT71gHw1BKfQUSaP4LuyVwS5I4WtvjM4Yced5mr yAftWXC5C+MzNAdv7S/7Azdg5uKLc7RhdHo8BuoC/N2aliA+VSpck2IQGW8pPkE5 kev2OuLL4Q/3IPpf52/qc9J/qO24XCA75+zrO1GKx/dWfIiezmJvXQC+YQIDAQAB AoGAYEpUgDuuQ8OlP2IO4tEuU64F3bOTZv3tX4HsTMMsi/nAv1XkqSQjNEBOL9UF V2sSCv7L6ammeeMgTPT4e7h6B71QSiRiS98lQn2vSJx1og1lncMDrIx5NjzduJtK pJEpWlfEF6RbqEqbJEcvreB4DXVQ6a3Uws8154jHosDXVKUCQQD2w/MJ2/EyDLqZ J+Wko7b+5YE5dEuSMsT09xP+PAZs5KEIkfwAhgyHEW2psxONXB8+PFytFJlAtctn aYCvZ2brAkEAyQk5TT3kZseJ+AIRtrsGz/gOyoek/aRe1AMmGZhMZeXn/dgwhzFm 7/5W7SpmWpj9IEY/761VQPmRWttgvYp04wJAGdhMDCxNBsDuijvzgVrkP64p6qqT f6xxlHaMUYRX5+/KLeucSTHA/iSFJ9Dpq1SKsSoBSt9tbamctCgIolZiIQJATIQm OzADbtsjuDGRbGti/GT9vDhEpAWb0jYgmj1NVrtawVM3pT04YL/9deddbb4tGcuj KiZe/IwAtwQonfvE4QJAKACxWfxZ/iM69ZvDLrbemF/F2t2h/5AV/t3ScjTmdkmG RBy6KVyMp0W/cVlmmSLgbKgIqZzKn9QdJYSedQ3Z7A== -----END RSA PRIVATE KEY----- This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,11 @@ -----BEGIN CERTIFICATE----- MIIBpzCCARACAQEwDQYJKoZIhvcNAQEEBQAwIDEeMBwGA1UEAxMVQ2VydGlmaWNh dGUgQXV0aG9yaXR5MB4XDTEzMDEyMjAwNTkzMVoXDTE4MDEyMTAwNTkzMVowGDEW MBQGA1UEAxMNU2ltcGxlIFNlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC gYEAodkur1u0xYaJBVsxQSUxHOASfzOJpA69k5XLkyD6kF729hMQ2jwf7Lx47YGb 8qloE9xGbQB8KxXX5BL5K/VxuDafDb51gCNBeuf7B3GMSduU3GJal0wiePlOWIgx kUkVZnuyeOYMSHbmV5udxXVXcaEGDk1UZ6LEQq0us5m6zCcCAwEAATANBgkqhkiG 9w0BAQQFAAOBgQAc83cXcCa9srzRyG3wGCFx8xNwQZl4d8AUDzpTrwufMWIqoRfU DIXYVfNqsBqfMSeOAjoX4HUtud4bHmPT2gi1yJEood4J2DeOMYvRYCQYS7hyaluI EyqZhoXClZtu2T1SdIAltxVBPqSCQQIjTD+KUEafeiQl6Cl722p6GIOGHQ== -----END CERTIFICATE----- This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQCh2S6vW7TFhokFWzFBJTEc4BJ/M4mkDr2TlcuTIPqQXvb2ExDa PB/svHjtgZvyqWgT3EZtAHwrFdfkEvkr9XG4Np8NvnWAI0F65/sHcYxJ25TcYlqX TCJ4+U5YiDGRSRVme7J45gxIduZXm53FdVdxoQYOTVRnosRCrS6zmbrMJwIDAQAB AoGATasFhk2B8JBhTNq4RkTszqiQ983prXsNarel29MlqwaHiQsZOUFFKLxBY+ig x9CYC3/XpBNpgtuWoPKh9IBys2rSx/4tE7lGm9UMzZ1uFBnNN9yT9hwRaHK8+xmA kjrftH5z8xj6Dtu6tovVMiwgtRQP46TtG8elCrcGHYpTDhECQQDNwKi+45yBx9TD DM/AACL7bv9bVfZ2rRS8Wuq4K8LWMp3ISkevFY6S58CVn+2gZOlL2cJ+C1QNkNiY BOqrMUFlAkEAyV+yyq8xk1ueuTOtlwvjFmGpcDg6yq9sxHwl6sG+JBNqu4K/jszb FjzK98Pe4vDcuJHV7+/Gp5L1KRlnHn4kmwJBAJPqvKW3Jo3apqeu7y/+KSgPbT8x dqVs2upqhjHvK/wnmW0jkZNacQxF1hr7Ra84vMvN+lf5Nu0lw8DOUBLQr00CQQCe T2+9zBFLaaHUs33q21uBwvFz2aDOqy71ISyl6/5RWjp0g4uY9g/e4ZgnRIM7ImRD bdMkt/oSz4OQ9fmNjVm1AkEArB0bO/Yq/g7BBrVYkaCEDN5wiOW27j59hXX8MqKM rgxMpUNctbuXSUdy6SK/XsicTgncGzNNZ/ztFsEUHZLdcw== -----END RSA PRIVATE KEY----- This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,50 @@ from __future__ import print_function import OpenSSL import pyuv import uvtls import signal import sys def shutdown_cb(handle, error): tls_h.close() def read_cb(handle, data, error): if error is not None: print("Read error: {}".format(pyuv.errno.strerror(error))) tls_h.close() return tls_h.write(data) print("Received data: {}".format(data)) if data.strip() == b'exit': tls_h.shutdown() def connect_cb(handle, error): if error is not None: print("Connection error: {}".format(pyuv.errno.strerror(error))) return print("Connected to {}".format(tls_h.getpeername())) tls_h.start_read(read_cb) def signal_cb(handle, signum): signal_h.close() tls_h.close() loop = pyuv.Loop.default_loop() ca = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open('ca.pem', 'r').read()) cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open('client.cert', 'r').read()) key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, open('client.pkey', 'r').read()) tls_h = uvtls.TLS(loop, cert=cert, key=key, ca_list=[ca]) tls_h.connect((sys.argv[1], int(sys.argv[2])), connect_cb) signal_h = pyuv.Signal(loop) signal_h.unref() signal_h.start(signal_cb, signal.SIGINT) loop.run() This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,61 @@ from __future__ import print_function import OpenSSL import pyuv import uvtls import signal import sys def shutdown_cb(handle, error): if not handle.closed: # Handle may already be closed if the remote didn't shutdown TLS # properly and cut the TCP connection instead handle.close() connections.remove(handle) def read_cb(handle, data, error): if error is not None: print("Read error: {}".format(pyuv.errno.strerror(error))) handle.close() return handle.write(data) print("Received data: {}".format(data)) if data.strip() == b'exit': handle.shutdown(shutdown_cb) def connection_cb(handle, error): if error is not None: print("Connection error: {}".format(pyuv.errno.strerror(error))) return tls_h = uvtls.TLS(loop) server.accept(tls_h) print("New connection from {}".format(tls_h.getpeername())) tls_h.start_read(read_cb) connections.append(tls_h) def signal_cb(handle, signum): signal_h.close() [c.close() for c in connections] server.close() connections = [] loop = pyuv.Loop.default_loop() ca = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open('CA.cert', 'r').read()) cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open('server.cert', 'r').read()) key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, open('server.pkey', 'r').read()) server = uvtls.TLS(loop, cert=cert, key=key, ca_list=[ca]) server.bind(('127.0.0.1', int(sys.argv[1]))) server.listen(connection_cb) print("Listening on {}".format(server.getsockname())) signal_h = pyuv.Signal(loop) signal_h.unref() signal_h.start(signal_cb, signal.SIGINT) loop.run() This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,231 @@ from __future__ import print_function import functools import OpenSSL import pyuv from OpenSSL.SSL import WantReadError, ZeroReturnError, Error, VERIFY_NONE _BIO_READ_SIZE = 2**15 def _true(*args): return True class TLS(object): def __init__(self, loop, key=None, cert=None, verify_mode=VERIFY_NONE, verify_callback=_true, version=OpenSSL.SSL.TLSv1_METHOD, ca_list=None): self.loop = loop self._tcp = pyuv.TCP(loop) ctx = OpenSSL.SSL.Context(version) if key is not None: ctx.use_privatekey(key) if cert is not None: ctx.use_certificate(cert) if key is not None and cert is not None: ctx.check_privatekey() if ca_list is not None: store = ctx.get_cert_store() for ca in ca_list: store.add_cert(ca) if not callable(verify_callback): raise ValueError('verify_calback needs to be callable') ctx.set_verify(verify_mode, verify_callback) self._connection = OpenSSL.SSL.Connection(ctx, None) self._lost_tls_connection = False self._handshake_done = False self._write_blocked_on_read = False self._send_buffer = [] self._saved_shutdown_cb = None def bind(self, address): self._tcp.bind(address) def listen(self, callback, backlog=128): self._tcp.listen(callback, backlog) def accept(self, client): self._connection.set_accept_state() self._tcp.accept(client._tcp) client._connection = OpenSSL.SSL.Connection(self._connection.get_context(), None) client._connection.set_accept_state() client._do_handshake() def connect(self, address, callback): self._connection.set_connect_state() self._tcp.connect(address, functools.partial(self._on_connect_cb, callback)) def shutdown(self, callback=None): assert self._saved_shutdown_cb is None, "shutdown was already called" self._saved_shutdown_cb = callback self._shutdown_tls() def write(self, data, callback=None): assert callback is None, "callback is not supported" if self._lost_tls_connection: return to_send = data while to_send: try: sent = self._connection.send(to_send) except WantReadError: self._write_blocked_on_read = True self._send_buffer.append(to_send) 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._tcp.close() break else: # If we sent some bytes, the handshake must be done. Keep # track of this to control error reporting behavior. self._handshake_done = True self._flush_send_bio() to_send = to_send[sent:] def writelines(self, seq, callback=None): raise NotImplementedError def start_read(self, callback): self._tcp.start_read(functools.partial(self._on_read_cb, callback)) def stop_read(self): self._tcp.stop_read() def close(self, callback=None): self._tcp.close(callback) def ref(self): self._tcp.ref() def unref(self): self._tcp.unref() def getsockname(self): return self._tcp.getsockname() def getpeername(self): return self._tcp.getpeername() def nodelay(self, enabled): self._tcp.nodelay(enabled) def keepalive(self, enabled, delay): self._tcp.keepalive(enabled, delay) def simultaneous_accepts(self, enabled): self._tcp.simultaneous_accepts(enabled) @property def readable(self): return self._tcp.readable @property def writable(self): return self._tcp.writable @property def active(self): return self._tcp.active @property def closed(self): return self._tcp.closed # Private def _do_handshake(self): try: self._connection.do_handshake() except WantReadError: # There is no data to complete the handshake, but there may be some # handshake bytes to be sent self._flush_send_bio() def _on_connect_cb(self, user_callback, handle, error): if error is not None: user_callback(handle, error) return # Start the SSL handshake self._do_handshake() # Call the user supplied callback user_callback(handle, error) def _on_read_cb(self, user_callback, handle, data, error): if error is not None: user_callback(self, data, error) return self._connection.bio_write(data) if self._write_blocked_on_read: self._write_blocked_on_read = False buf, self._send_buffer = self._send_buffer, [] for item in buf: self.write(item) self._flush_receive_bio(user_callback) def _shutdown_tls(self): success = self._connection.shutdown() self._flush_send_bio() if success: self._tcp.shutdown(self._shutdown_cb) def _shutdown_cb(self, handle, error): if self._saved_shutdown_cb is not None: self._saved_shutdown_cb(self, error) def _flush_send_bio(self, callback=None): try: data = self._connection.bio_read(_BIO_READ_SIZE) except WantReadError: pass else: self._tcp.write(data, callback) def _flush_receive_bio(self, callback): # 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._lost_tls_connection: try: data = self._connection.recv(_BIO_READ_SIZE) 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._shutdown_tls() self._lost_tls_connection = True except Error as e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. # TODO: what to do with the exception? print("OpenSSL error: {}".format(e)) self._flush_send_bio() self._lost_tls_connection = True self._tcp.close() else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. self._handshake_done = True callback(self, data, None) # 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._flush_send_bio()