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