1
2
3
4
5
6
7 """TLS Lite + asyncore."""
8
9
10 import asyncore
11 from tlslite.tlsconnection import TLSConnection
12 from .asyncstatemachine import AsyncStateMachine
13
14
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
98
100 result = self.wantsReadEvent()
101 if result != None:
102 return result
103 return self.siblingClass.readable(self)
104
106 result = self.wantsWriteEvent()
107 if result != None:
108 return result
109 return self.siblingClass.writable(self)
110
113
116
118 self.siblingClass.handle_connect(self)
119
121 asyncore.dispatcher.close(self)
122
124 self.readBuffer = readBuffer
125 self.siblingClass.handle_read(self)
126
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
142 if hasattr(self, "tlsConnection"):
143 self.setCloseOp()
144 else:
145 asyncore.dispatcher.close(self)
146