1"""TLS Lite + asyncore.""" 2 3 4import asyncore 5from tlslite.TLSConnection import TLSConnection 6from AsyncStateMachine import AsyncStateMachine 7 8 9class TLSAsyncDispatcherMixIn(AsyncStateMachine): 10 """This class can be "mixed in" with an 11 L{asyncore.dispatcher} to add TLS support. 12 13 This class essentially sits between the dispatcher and the select 14 loop, intercepting events and only calling the dispatcher when 15 applicable. 16 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. 21 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 24 activated. 25 26 To use this class, you must combine it with an asyncore.dispatcher, 27 and pass in a handshake operation with setServerHandshakeOp(). 28 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 32 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. 36 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 39 be displayed on IE. 40 41 Add the following text into 'start_medusa.py', in the 'HTTP Server' 42 section:: 43 44 from tlslite.api import * 45 s = open("./serverX509Cert.pem").read() 46 x509 = X509() 47 x509.parse(s) 48 certChain = X509CertChain([x509]) 49 50 s = open("./serverX509Key.pem").read() 51 privateKey = parsePEMKey(s, private=True) 52 53 class http_tls_channel(TLSAsyncDispatcherMixIn, 54 http_server.http_channel): 55 ac_in_buffer_size = 16384 56 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) 63 64 hs.channel_class = http_tls_channel 65 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. 72 73 """ 74 75 76 def __init__(self, sock=None): 77 AsyncStateMachine.__init__(self) 78 79 if sock: 80 self.tlsConnection = TLSConnection(sock) 81 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 89 break 90 else: 91 raise AssertionError() 92 93 def readable(self): 94 result = self.wantsReadEvent() 95 if result != None: 96 return result 97 return self.siblingClass.readable(self) 98 99 def writable(self): 100 result = self.wantsWriteEvent() 101 if result != None: 102 return result 103 return self.siblingClass.writable(self) 104 105 def handle_read(self): 106 self.inReadEvent() 107 108 def handle_write(self): 109 self.inWriteEvent() 110 111 def outConnectEvent(self): 112 self.siblingClass.handle_connect(self) 113 114 def outCloseEvent(self): 115 asyncore.dispatcher.close(self) 116 117 def outReadEvent(self, readBuffer): 118 self.readBuffer = readBuffer 119 self.siblingClass.handle_read(self) 120 121 def outWriteEvent(self): 122 self.siblingClass.handle_write(self) 123 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 129 return returnValue 130 131 def send(self, writeBuffer): 132 self.setWriteOp(writeBuffer) 133 return len(writeBuffer) 134 135 def close(self): 136 if hasattr(self, "tlsConnection"): 137 self.setCloseOp() 138 else: 139 asyncore.dispatcher.close(self)