1# Authors: 2# Trevor Perrin 3# Martin von Loewis - python 3 port 4# 5# See the LICENSE file for legal information regarding use of this file. 6 7"""TLS Lite + asyncore.""" 8 9 10import asyncore 11from tlslite.tlsconnection import TLSConnection 12from .asyncstatemachine import AsyncStateMachine 13 14 15class TLSAsyncDispatcherMixIn(AsyncStateMachine): 16 """This class can be "mixed in" with an 17 L{asyncore.dispatcher} to add TLS support. 18 19 This class essentially sits between the dispatcher and the select 20 loop, intercepting events and only calling the dispatcher when 21 applicable. 22 23 In the case of handle_read(), a read operation will be activated, 24 and when it completes, the bytes will be placed in a buffer where 25 the dispatcher can retrieve them by calling recv(), and the 26 dispatcher's handle_read() will be called. 27 28 In the case of handle_write(), the dispatcher's handle_write() will 29 be called, and when it calls send(), a write operation will be 30 activated. 31 32 To use this class, you must combine it with an asyncore.dispatcher, 33 and pass in a handshake operation with setServerHandshakeOp(). 34 35 Below is an example of using this class with medusa. This class is 36 mixed in with http_channel to create http_tls_channel. Note: 37 1. the mix-in is listed first in the inheritance list 38 39 2. the input buffer size must be at least 16K, otherwise the 40 dispatcher might not read all the bytes from the TLS layer, 41 leaving some bytes in limbo. 42 43 3. IE seems to have a problem receiving a whole HTTP response in a 44 single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't 45 be displayed on IE. 46 47 Add the following text into 'start_medusa.py', in the 'HTTP Server' 48 section:: 49 50 from tlslite import * 51 s = open("./serverX509Cert.pem").read() 52 x509 = X509() 53 x509.parse(s) 54 certChain = X509CertChain([x509]) 55 56 s = open("./serverX509Key.pem").read() 57 privateKey = parsePEMKey(s, private=True) 58 59 class http_tls_channel(TLSAsyncDispatcherMixIn, 60 http_server.http_channel): 61 ac_in_buffer_size = 16384 62 63 def __init__ (self, server, conn, addr): 64 http_server.http_channel.__init__(self, server, conn, addr) 65 TLSAsyncDispatcherMixIn.__init__(self, conn) 66 self.tlsConnection.ignoreAbruptClose = True 67 self.setServerHandshakeOp(certChain=certChain, 68 privateKey=privateKey) 69 70 hs.channel_class = http_tls_channel 71 72 If the TLS layer raises an exception, the exception will be caught 73 in asyncore.dispatcher, which will call close() on this class. The 74 TLS layer always closes the TLS connection before raising an 75 exception, so the close operation will complete right away, causing 76 asyncore.dispatcher.close() to be called, which closes the socket 77 and removes this instance from the asyncore loop. 78 79 """ 80 81 82 def __init__(self, sock=None): 83 AsyncStateMachine.__init__(self) 84 85 if sock: 86 self.tlsConnection = TLSConnection(sock) 87 88 #Calculate the sibling I'm being mixed in with. 89 #This is necessary since we override functions 90 #like readable(), handle_read(), etc., but we 91 #also want to call the sibling's versions. 92 for cl in self.__class__.__bases__: 93 if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine: 94 self.siblingClass = cl 95 break 96 else: 97 raise AssertionError() 98 99 def readable(self): 100 result = self.wantsReadEvent() 101 if result != None: 102 return result 103 return self.siblingClass.readable(self) 104 105 def writable(self): 106 result = self.wantsWriteEvent() 107 if result != None: 108 return result 109 return self.siblingClass.writable(self) 110 111 def handle_read(self): 112 self.inReadEvent() 113 114 def handle_write(self): 115 self.inWriteEvent() 116 117 def outConnectEvent(self): 118 self.siblingClass.handle_connect(self) 119 120 def outCloseEvent(self): 121 asyncore.dispatcher.close(self) 122 123 def outReadEvent(self, readBuffer): 124 self.readBuffer = readBuffer 125 self.siblingClass.handle_read(self) 126 127 def outWriteEvent(self): 128 self.siblingClass.handle_write(self) 129 130 def recv(self, bufferSize=16384): 131 if bufferSize < 16384 or self.readBuffer == None: 132 raise AssertionError() 133 returnValue = self.readBuffer 134 self.readBuffer = None 135 return returnValue 136 137 def send(self, writeBuffer): 138 self.setWriteOp(writeBuffer) 139 return len(writeBuffer) 140 141 def close(self): 142 if hasattr(self, "tlsConnection"): 143 self.setCloseOp() 144 else: 145 asyncore.dispatcher.close(self) 146