Howdy list,<br><br>I'm trying to implement a protocol using Twisted which has a "STARTTLS" command to switch the protocol from plain TCP to TCP over TLS.<br><br>I've mostly been going by the way that the imap4.py module seems to do it, but I can't seem to get a handshake to complete.<br>
<br>I found this page ( <a href="http://wiki.vislab.usyd.edu.au/moin.cgi/SSLCertNotes">http://wiki.vislab.usyd.edu.au/moin.cgi/SSLCertNotes</a> ) which was helpful, but I don't want to force client cert authentication.<br>
<br>In order to separate this problem from other issues, I've adapted the echo protocol code from above the above page to try and get a simple test case (my code below)<br><br>I am recieving the following output and traceback when running the client code ( on both Windows and Linux ):<br>
<br>using TLSv1:<br><br>>tls_echoclient.py<br><br>Sending: Hello, world!<br>receive: ERROR: Must authenticate<br>Sending: STARTTLS<br>receive: READY<br>Sending: Continuing<br>connection lost (protocol)<br>connection lost: [('SSL routines', 'SSL3_READ_BYTES', 'sslv3 alert handshake failure'), ('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')]<br>
Traceback (most recent call last):<br> File "C:\Documents and Settings\kevinh\Desktop\mine_id\sandbox\funsize\sslecho\tls_echoclient.py", line 58, in <module><br> reactor.run()<br> File "C:\Python25\lib\site-packages\twisted\internet\posixbase.py", line 223, in run<br>
self.mainLoop()<br> File "C:\Python25\lib\site-packages\twisted\internet\posixbase.py", line 234, in mainLoop<br> self.doIteration(t)<br> File "C:\Python25\lib\site-packages\twisted\internet\selectreactor.py", line 140, in doSelect<br>
_logrun(selectable, _drdw, selectable, method, dict)<br>--- <exception caught here> ---<br> File "C:\Python25\lib\site-packages\twisted\python\log.py", line 51, in callWithLogger<br> return callWithContext({"system": lp}, func, *args, **kw)<br>
<< SNIP >><br> File "C:\Python25\lib\site-packages\twisted\internet\base.py", line 490, in stop<br> "Can't stop reactor that isn't running.")<br>twisted.internet.error.ReactorNotRunning: Can't stop reactor that isn't running.<br>
<br>What am I doing wrong? Is there a SSL config option I'm setting incorrectly? Do I need to use a different SSL Context? Am I totally off base?<br><br>Thanks, <br><br>Kevin Horn<br><br>========= tls_echoserver.py<br>
<br># adapted from: <a href="http://wiki.vislab.usyd.edu.au/moin.cgi/SSLCertNotes">http://wiki.vislab.usyd.edu.au/moin.cgi/SSLCertNotes</a><br><br>import sys<br>from OpenSSL import SSL<br>from twisted.python import log<br>
from twisted.internet import ssl, reactor<br>from twisted.protocols.basic import LineReceiver<br>from twisted.internet.protocol import Factory<br><br>private_key_file = "privkey_dsa.pem"<br>cert_file_name = "cacert.pem"<br>
sslmethod = ssl.SSL.TLSv1_METHOD<br>#~ sslmethod = ssl.SSL.SSLv23_METHOD<br><br>class Echo(LineReceiver):<br> donetls = 0<br> def sendLine(self, line):<br> print "Sending:",line<br> LineReceiver.sendLine(self,line)<br>
<br> def lineReceived(self, line):<br> print "Got:",line<br> if self.donetls:<br> print "Sending OK"<br> self.transport.write("OK")<br> elif line == "STARTTLS":<br>
self.sendLine("READY")<br> #~ self.tlsCtx = CtxFactory()<br> self.tlsCtx = ssl.DefaultOpenSSLContextFactory(private_key_file, <br> cert_file_name,<br>
sslmethod)<br> self.transport.startTLS(self.tlsCtx)<br> self.donetls = 1<br> else:<br> self.sendLine("ERROR: Must authenticate")<br>
<br>factory = Factory()<br>factory.protocol = Echo<br>reactor.listenTCP(8000, factory)<br>reactor.run()<br><br>========= tls_echoclient.py<br><br># adapted from: <a href="http://wiki.vislab.usyd.edu.au/moin.cgi/SSLCertNotes">http://wiki.vislab.usyd.edu.au/moin.cgi/SSLCertNotes</a><br>
<br>from OpenSSL import SSL<br>import sys<br><br>from twisted.internet.protocol import ClientFactory<br>from twisted.protocols.basic import LineReceiver<br>from twisted.internet import ssl, reactor<br><br>class EchoClient(LineReceiver):<br>
end="Bye-bye!"<br> def connectionMade(self):<br> self.sendLine("Hello, world!") # Signals error<br><br> def connectionLost(self, reason):<br> print 'connection lost (protocol)'<br>
reactor.stop()<br><br> def sendLine(self, line):<br> print "Sending:",line<br> LineReceiver.sendLine(self,line)<br><br> def lineReceived(self, line):<br> print "receive:", line<br>
if line == "ERROR: Must authenticate":<br> self.sendLine("STARTTLS")<br> elif line == "READY":<br> #~ self.ctx = CxtFactory()<br> self.ctx = ssl.ClientContextFactory()<br>
self.ctx.method = ssl.SSL.TLSv1_METHOD<br> #~ self.ctx.method = ssl.SSL.SSLv23_METHOD<br> self.transport.startTLS(self.ctx)<br> self.sendLine("Continuing");<br> else:<br>
self.sendLine("wibble")<br><br>class EchoClientFactory(ClientFactory):<br> protocol = EchoClient<br><br> def clientConnectionFailed(self, connector, reason):<br> print 'connection failed:', reason.getErrorMessage()<br>
reactor.stop()<br><br> def clientConnectionLost(self, connector, reason):<br> print 'connection lost:', reason.getErrorMessage()<br> reactor.stop()<br><br>factory = EchoClientFactory()<br>
reactor.connectTCP('localhost', 8000, factory)<br>reactor.run()<br>