15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""TLS Lite + asyncore."""
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import asyncore
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from tlslite.TLSConnection import TLSConnection
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from AsyncStateMachine import AsyncStateMachine
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TLSAsyncDispatcherMixIn(AsyncStateMachine):
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """This class can be "mixed in" with an
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    L{asyncore.dispatcher} to add TLS support.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This class essentially sits between the dispatcher and the select
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    loop, intercepting events and only calling the dispatcher when
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    applicable.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    In the case of handle_read(), a read operation will be activated,
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and when it completes, the bytes will be placed in a buffer where
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the dispatcher can retrieve them by calling recv(), and the
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dispatcher's handle_read() will be called.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    In the case of handle_write(), the dispatcher's handle_write() will
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    be called, and when it calls send(), a write operation will be
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    activated.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    To use this class, you must combine it with an asyncore.dispatcher,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and pass in a handshake operation with setServerHandshakeOp().
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Below is an example of using this class with medusa.  This class is
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mixed in with http_channel to create http_tls_channel.  Note:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     1. the mix-in is listed first in the inheritance list
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     2. the input buffer size must be at least 16K, otherwise the
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       dispatcher might not read all the bytes from the TLS layer,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       leaving some bytes in limbo.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     3. IE seems to have a problem receiving a whole HTTP response in a
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     be displayed on IE.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Add the following text into 'start_medusa.py', in the 'HTTP Server'
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    section::
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        from tlslite.api import *
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        s = open("./serverX509Cert.pem").read()
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x509 = X509()
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x509.parse(s)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        certChain = X509CertChain([x509])
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        s = open("./serverX509Key.pem").read()
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        privateKey = parsePEMKey(s, private=True)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        class http_tls_channel(TLSAsyncDispatcherMixIn,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               http_server.http_channel):
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ac_in_buffer_size = 16384
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            def __init__ (self, server, conn, addr):
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                http_server.http_channel.__init__(self, server, conn, addr)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                TLSAsyncDispatcherMixIn.__init__(self, conn)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                self.tlsConnection.ignoreAbruptClose = True
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                self.setServerHandshakeOp(certChain=certChain,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          privateKey=privateKey)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hs.channel_class = http_tls_channel
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If the TLS layer raises an exception, the exception will be caught
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in asyncore.dispatcher, which will call close() on this class.  The
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TLS layer always closes the TLS connection before raising an
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exception, so the close operation will complete right away, causing
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asyncore.dispatcher.close() to be called, which closes the socket
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and removes this instance from the asyncore loop.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __init__(self, sock=None):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AsyncStateMachine.__init__(self)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if sock:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.tlsConnection = TLSConnection(sock)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        #Calculate the sibling I'm being mixed in with.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        #This is necessary since we override functions
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        #like readable(), handle_read(), etc., but we
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        #also want to call the sibling's versions.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for cl in self.__class__.__bases__:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                self.siblingClass = cl
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            raise AssertionError()
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def readable(self):
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result = self.wantsReadEvent()
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if result != None:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return result
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return self.siblingClass.readable(self)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def writable(self):
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result = self.wantsWriteEvent()
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if result != None:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return result
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return self.siblingClass.writable(self)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def handle_read(self):
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.inReadEvent()
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def handle_write(self):
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.inWriteEvent()
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def outConnectEvent(self):
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.siblingClass.handle_connect(self)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def outCloseEvent(self):
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asyncore.dispatcher.close(self)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def outReadEvent(self, readBuffer):
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.readBuffer = readBuffer
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.siblingClass.handle_read(self)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def outWriteEvent(self):
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.siblingClass.handle_write(self)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def recv(self, bufferSize=16384):
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if bufferSize < 16384 or self.readBuffer == None:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            raise AssertionError()
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        returnValue = self.readBuffer
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.readBuffer = None
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return returnValue
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def send(self, writeBuffer):
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.setWriteOp(writeBuffer)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return len(writeBuffer)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def close(self):
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if hasattr(self, "tlsConnection"):
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.setCloseOp()
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            asyncore.dispatcher.close(self)