Howdy list,<br><br>I&#39;m trying to implement a protocol using Twisted which has a &quot;STARTTLS&quot; command to switch the protocol from plain TCP to TCP over TLS.<br><br>I&#39;ve mostly been going by the way that the imap4.py module seems to do it, but I can&#39;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&#39;t want to force client cert authentication.<br>
<br>In order to separate this problem from other issues, I&#39;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>&gt;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: [(&#39;SSL routines&#39;, &#39;SSL3_READ_BYTES&#39;, &#39;sslv3 alert handshake failure&#39;), (&#39;SSL routines&#39;, &#39;SSL3_READ_BYTES&#39;, &#39;ssl handshake failure&#39;)]<br>
Traceback (most recent call last):<br>&nbsp; File &quot;C:\Documents and Settings\kevinh\Desktop\mine_id\sandbox\funsize\sslecho\tls_echoclient.py&quot;, line 58, in &lt;module&gt;<br>&nbsp;&nbsp;&nbsp; reactor.run()<br>&nbsp; File &quot;C:\Python25\lib\site-packages\twisted\internet\posixbase.py&quot;, line 223, in run<br>
&nbsp;&nbsp;&nbsp; self.mainLoop()<br>&nbsp; File &quot;C:\Python25\lib\site-packages\twisted\internet\posixbase.py&quot;, line 234, in mainLoop<br>&nbsp;&nbsp;&nbsp; self.doIteration(t)<br>&nbsp; File &quot;C:\Python25\lib\site-packages\twisted\internet\selectreactor.py&quot;, line 140, in doSelect<br>
&nbsp;&nbsp;&nbsp; _logrun(selectable, _drdw, selectable, method, dict)<br>--- &lt;exception caught here&gt; ---<br>&nbsp; File &quot;C:\Python25\lib\site-packages\twisted\python\log.py&quot;, line 51, in callWithLogger<br>&nbsp;&nbsp;&nbsp; return callWithContext({&quot;system&quot;: lp}, func, *args, **kw)<br>
&lt;&lt; SNIP &gt;&gt;<br>&nbsp; File &quot;C:\Python25\lib\site-packages\twisted\internet\base.py&quot;, line 490, in stop<br>&nbsp;&nbsp;&nbsp; &quot;Can&#39;t stop reactor that isn&#39;t running.&quot;)<br>twisted.internet.error.ReactorNotRunning: Can&#39;t stop reactor that isn&#39;t running.<br>
<br>What am I doing wrong?&nbsp; Is there a SSL config option I&#39;m setting incorrectly?&nbsp; 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 = &quot;privkey_dsa.pem&quot;<br>cert_file_name = &quot;cacert.pem&quot;<br>
sslmethod = ssl.SSL.TLSv1_METHOD<br>#~ sslmethod = ssl.SSL.SSLv23_METHOD<br><br>class Echo(LineReceiver):<br>&nbsp;&nbsp;&nbsp; donetls = 0<br>&nbsp;&nbsp;&nbsp; def sendLine(self, line):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;Sending:&quot;,line<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LineReceiver.sendLine(self,line)<br>
<br>&nbsp;&nbsp;&nbsp; def lineReceived(self, line):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;Got:&quot;,line<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.donetls:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;Sending OK&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.transport.write(&quot;OK&quot;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif line == &quot;STARTTLS&quot;:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sendLine(&quot;READY&quot;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #~ self.tlsCtx = CtxFactory()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.tlsCtx = ssl.DefaultOpenSSLContextFactory(private_key_file, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cert_file_name,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sslmethod)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.transport.startTLS(self.tlsCtx)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.donetls = 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sendLine(&quot;ERROR: Must authenticate&quot;)<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>
&nbsp;&nbsp;&nbsp; end=&quot;Bye-bye!&quot;<br>&nbsp;&nbsp;&nbsp; def connectionMade(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sendLine(&quot;Hello, world!&quot;)&nbsp; # Signals error<br><br>&nbsp;&nbsp;&nbsp; def connectionLost(self, reason):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &#39;connection lost (protocol)&#39;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reactor.stop()<br><br>&nbsp;&nbsp;&nbsp; def sendLine(self, line):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;Sending:&quot;,line<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LineReceiver.sendLine(self,line)<br><br>&nbsp;&nbsp;&nbsp; def lineReceived(self, line):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;receive:&quot;, line<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if line == &quot;ERROR: Must authenticate&quot;:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sendLine(&quot;STARTTLS&quot;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif line == &quot;READY&quot;:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #~ self.ctx = CxtFactory()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.ctx = ssl.ClientContextFactory()<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.ctx.method = ssl.SSL.TLSv1_METHOD<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #~ self.ctx.method = ssl.SSL.SSLv23_METHOD<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.transport.startTLS(self.ctx)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sendLine(&quot;Continuing&quot;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sendLine(&quot;wibble&quot;)<br><br>class EchoClientFactory(ClientFactory):<br>&nbsp;&nbsp;&nbsp; protocol = EchoClient<br><br>&nbsp;&nbsp;&nbsp; def clientConnectionFailed(self, connector, reason):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &#39;connection failed:&#39;, reason.getErrorMessage()<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reactor.stop()<br><br>&nbsp;&nbsp;&nbsp; def clientConnectionLost(self, connector, reason):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &#39;connection lost:&#39;, reason.getErrorMessage()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reactor.stop()<br><br>factory = EchoClientFactory()<br>
reactor.connectTCP(&#39;localhost&#39;, 8000, factory)<br>reactor.run()<br>