1 """TLS Lite + asyncore."""
5 from tlslite.TLSConnection import TLSConnection
6 from AsyncStateMachine import AsyncStateMachine
9 class TLSAsyncDispatcherMixIn(AsyncStateMachine):
10 """This class can be "mixed in" with an
11 L{asyncore.dispatcher} to add TLS support.
13 This class essentially sits between the dispatcher and the select
14 loop, intercepting events and only calling the dispatcher when
17 In the case of handle_read(), a read operation will be activated,
18 and when it completes, the bytes will be placed in a buffer where
19 the dispatcher can retrieve them by calling recv(), and the
20 dispatcher's handle_read() will be called.
22 In the case of handle_write(), the dispatcher's handle_write() will
23 be called, and when it calls send(), a write operation will be
26 To use this class, you must combine it with an asyncore.dispatcher,
27 and pass in a handshake operation with setServerHandshakeOp().
29 Below is an example of using this class with medusa. This class is
30 mixed in with http_channel to create http_tls_channel. Note:
31 1. the mix-in is listed first in the inheritance list
33 2. the input buffer size must be at least 16K, otherwise the
34 dispatcher might not read all the bytes from the TLS layer,
35 leaving some bytes in limbo.
37 3. IE seems to have a problem receiving a whole HTTP response in a
38 single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't
41 Add the following text into 'start_medusa.py', in the 'HTTP Server'
44 from tlslite.api import *
45 s = open("./serverX509Cert.pem").read()
48 certChain = X509CertChain([x509])
50 s = open("./serverX509Key.pem").read()
51 privateKey = parsePEMKey(s, private=True)
53 class http_tls_channel(TLSAsyncDispatcherMixIn,
54 http_server.http_channel):
55 ac_in_buffer_size = 16384
57 def __init__ (self, server, conn, addr):
58 http_server.http_channel.__init__(self, server, conn, addr)
59 TLSAsyncDispatcherMixIn.__init__(self, conn)
60 self.tlsConnection.ignoreAbruptClose = True
61 self.setServerHandshakeOp(certChain=certChain,
62 privateKey=privateKey)
64 hs.channel_class = http_tls_channel
66 If the TLS layer raises an exception, the exception will be caught
67 in asyncore.dispatcher, which will call close() on this class. The
68 TLS layer always closes the TLS connection before raising an
69 exception, so the close operation will complete right away, causing
70 asyncore.dispatcher.close() to be called, which closes the socket
71 and removes this instance from the asyncore loop.
76 def __init__(self, sock=None):
77 AsyncStateMachine.__init__(self)
80 self.tlsConnection = TLSConnection(sock)
82 #Calculate the sibling I'm being mixed in with.
83 #This is necessary since we override functions
84 #like readable(), handle_read(), etc., but we
85 #also want to call the sibling's versions.
86 for cl in self.__class__.__bases__:
87 if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine:
88 self.siblingClass = cl
91 raise AssertionError()
94 result = self.wantsReadEvent()
97 return self.siblingClass.readable(self)
100 result = self.wantsWriteEvent()
103 return self.siblingClass.writable(self)
105 def handle_read(self):
108 def handle_write(self):
111 def outConnectEvent(self):
112 self.siblingClass.handle_connect(self)
114 def outCloseEvent(self):
115 asyncore.dispatcher.close(self)
117 def outReadEvent(self, readBuffer):
118 self.readBuffer = readBuffer
119 self.siblingClass.handle_read(self)
121 def outWriteEvent(self):
122 self.siblingClass.handle_write(self)
124 def recv(self, bufferSize=16384):
125 if bufferSize < 16384 or self.readBuffer == None:
126 raise AssertionError()
127 returnValue = self.readBuffer
128 self.readBuffer = None
131 def send(self, writeBuffer):
132 self.setWriteOp(writeBuffer)
133 return len(writeBuffer)
136 if hasattr(self, "tlsConnection"):
139 asyncore.dispatcher.close(self)