OLD | NEW |
| (Empty) |
1 """TLS Lite + Twisted.""" | |
2 | |
3 from twisted.protocols.policies import ProtocolWrapper, WrappingFactory | |
4 from twisted.python.failure import Failure | |
5 | |
6 from asyncstatemachine import AsyncStateMachine | |
7 from tlslite.tlsconnection import TLSConnection | |
8 from tlslite.errors import * | |
9 | |
10 import socket | |
11 import errno | |
12 | |
13 | |
14 #The TLSConnection is created around a "fake socket" that | |
15 #plugs it into the underlying Twisted transport | |
16 class _FakeSocket: | |
17 def __init__(self, wrapper): | |
18 self.wrapper = wrapper | |
19 self.data = "" | |
20 | |
21 def send(self, data): | |
22 ProtocolWrapper.write(self.wrapper, data) | |
23 return len(data) | |
24 | |
25 def recv(self, numBytes): | |
26 if self.data == "": | |
27 raise socket.error, (errno.EWOULDBLOCK, "") | |
28 returnData = self.data[:numBytes] | |
29 self.data = self.data[numBytes:] | |
30 return returnData | |
31 | |
32 class TLSTwistedProtocolWrapper(ProtocolWrapper, AsyncStateMachine): | |
33 """This class can wrap Twisted protocols to add TLS support. | |
34 | |
35 Below is a complete example of using TLS Lite with a Twisted echo | |
36 server. | |
37 | |
38 There are two server implementations below. Echo is the original | |
39 protocol, which is oblivious to TLS. Echo1 subclasses Echo and | |
40 negotiates TLS when the client connects. Echo2 subclasses Echo and | |
41 negotiates TLS when the client sends "STARTTLS":: | |
42 | |
43 from twisted.internet.protocol import Protocol, Factory | |
44 from twisted.internet import reactor | |
45 from twisted.protocols.policies import WrappingFactory | |
46 from twisted.protocols.basic import LineReceiver | |
47 from twisted.python import log | |
48 from twisted.python.failure import Failure | |
49 import sys | |
50 from tlslite.api import * | |
51 | |
52 s = open("./serverX509Cert.pem").read() | |
53 x509 = X509() | |
54 x509.parse(s) | |
55 certChain = X509CertChain([x509]) | |
56 | |
57 s = open("./serverX509Key.pem").read() | |
58 privateKey = parsePEMKey(s, private=True) | |
59 | |
60 verifierDB = VerifierDB("verifierDB") | |
61 verifierDB.open() | |
62 | |
63 class Echo(LineReceiver): | |
64 def connectionMade(self): | |
65 self.transport.write("Welcome to the echo server!\\r\\n") | |
66 | |
67 def lineReceived(self, line): | |
68 self.transport.write(line + "\\r\\n") | |
69 | |
70 class Echo1(Echo): | |
71 def connectionMade(self): | |
72 if not self.transport.tlsStarted: | |
73 self.transport.setServerHandshakeOp(certChain=certChain, | |
74 privateKey=privateKey, | |
75 verifierDB=verifierDB) | |
76 else: | |
77 Echo.connectionMade(self) | |
78 | |
79 def connectionLost(self, reason): | |
80 pass #Handle any TLS exceptions here | |
81 | |
82 class Echo2(Echo): | |
83 def lineReceived(self, data): | |
84 if data == "STARTTLS": | |
85 self.transport.setServerHandshakeOp(certChain=certChain, | |
86 privateKey=privateKey, | |
87 verifierDB=verifierDB) | |
88 else: | |
89 Echo.lineReceived(self, data) | |
90 | |
91 def connectionLost(self, reason): | |
92 pass #Handle any TLS exceptions here | |
93 | |
94 factory = Factory() | |
95 factory.protocol = Echo1 | |
96 #factory.protocol = Echo2 | |
97 | |
98 wrappingFactory = WrappingFactory(factory) | |
99 wrappingFactory.protocol = TLSTwistedProtocolWrapper | |
100 | |
101 log.startLogging(sys.stdout) | |
102 reactor.listenTCP(1079, wrappingFactory) | |
103 reactor.run() | |
104 | |
105 This class works as follows: | |
106 | |
107 Data comes in and is given to the AsyncStateMachine for handling. | |
108 AsyncStateMachine will forward events to this class, and we'll | |
109 pass them on to the ProtocolHandler, which will proxy them to the | |
110 wrapped protocol. The wrapped protocol may then call back into | |
111 this class, and these calls will be proxied into the | |
112 AsyncStateMachine. | |
113 | |
114 The call graph looks like this: | |
115 - self.dataReceived | |
116 - AsyncStateMachine.inReadEvent | |
117 - self.out(Connect|Close|Read)Event | |
118 - ProtocolWrapper.(connectionMade|loseConnection|dataReceived) | |
119 - self.(loseConnection|write|writeSequence) | |
120 - AsyncStateMachine.(setCloseOp|setWriteOp) | |
121 """ | |
122 | |
123 #WARNING: IF YOU COPY-AND-PASTE THE ABOVE CODE, BE SURE TO REMOVE | |
124 #THE EXTRA ESCAPING AROUND "\\r\\n" | |
125 | |
126 def __init__(self, factory, wrappedProtocol): | |
127 ProtocolWrapper.__init__(self, factory, wrappedProtocol) | |
128 AsyncStateMachine.__init__(self) | |
129 self.fakeSocket = _FakeSocket(self) | |
130 self.tlsConnection = TLSConnection(self.fakeSocket) | |
131 self.tlsStarted = False | |
132 self.connectionLostCalled = False | |
133 | |
134 def connectionMade(self): | |
135 try: | |
136 ProtocolWrapper.connectionMade(self) | |
137 except TLSError, e: | |
138 self.connectionLost(Failure(e)) | |
139 ProtocolWrapper.loseConnection(self) | |
140 | |
141 def dataReceived(self, data): | |
142 try: | |
143 if not self.tlsStarted: | |
144 ProtocolWrapper.dataReceived(self, data) | |
145 else: | |
146 self.fakeSocket.data += data | |
147 while self.fakeSocket.data: | |
148 AsyncStateMachine.inReadEvent(self) | |
149 except TLSError, e: | |
150 self.connectionLost(Failure(e)) | |
151 ProtocolWrapper.loseConnection(self) | |
152 | |
153 def connectionLost(self, reason): | |
154 if not self.connectionLostCalled: | |
155 ProtocolWrapper.connectionLost(self, reason) | |
156 self.connectionLostCalled = True | |
157 | |
158 | |
159 def outConnectEvent(self): | |
160 ProtocolWrapper.connectionMade(self) | |
161 | |
162 def outCloseEvent(self): | |
163 ProtocolWrapper.loseConnection(self) | |
164 | |
165 def outReadEvent(self, data): | |
166 if data == "": | |
167 ProtocolWrapper.loseConnection(self) | |
168 else: | |
169 ProtocolWrapper.dataReceived(self, data) | |
170 | |
171 | |
172 def setServerHandshakeOp(self, **args): | |
173 self.tlsStarted = True | |
174 AsyncStateMachine.setServerHandshakeOp(self, **args) | |
175 | |
176 def loseConnection(self): | |
177 if not self.tlsStarted: | |
178 ProtocolWrapper.loseConnection(self) | |
179 else: | |
180 AsyncStateMachine.setCloseOp(self) | |
181 | |
182 def write(self, data): | |
183 if not self.tlsStarted: | |
184 ProtocolWrapper.write(self, data) | |
185 else: | |
186 #Because of the FakeSocket, write operations are guaranteed to | |
187 #terminate immediately. | |
188 AsyncStateMachine.setWriteOp(self, data) | |
189 | |
190 def writeSequence(self, seq): | |
191 if not self.tlsStarted: | |
192 ProtocolWrapper.writeSequence(self, seq) | |
193 else: | |
194 #Because of the FakeSocket, write operations are guaranteed to | |
195 #terminate immediately. | |
196 AsyncStateMachine.setWriteOp(self, "".join(seq)) | |
OLD | NEW |