summaryrefslogtreecommitdiff
path: root/doc/core/howto/ssl.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/core/howto/ssl.html')
-rw-r--r--doc/core/howto/ssl.html550
1 files changed, 550 insertions, 0 deletions
diff --git a/doc/core/howto/ssl.html b/doc/core/howto/ssl.html
new file mode 100644
index 0000000..6744ad3
--- /dev/null
+++ b/doc/core/howto/ssl.html
@@ -0,0 +1,550 @@
+<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+<title>Twisted Documentation: Using SSL in Twisted</title>
+<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
+ </head>
+
+ <body bgcolor="white">
+ <h1 class="title">Using SSL in Twisted</h1>
+ <div class="toc"><ol><li><a href="#auto0">Overview</a></li><li><a href="#auto1">SSL echo server and client without client authentication</a></li><ul><li><a href="#auto2">SSL echo server</a></li><li><a href="#auto3">SSL echo client</a></li></ul><li><a href="#auto4">Using startTLS</a></li><ul><li><a href="#auto5">startTLS server</a></li><li><a href="#auto6">startTLS client</a></li></ul><li><a href="#auto7">Client authentication</a></li><ul><li><a href="#auto8">Client-authenticating server</a></li><li><a href="#auto9">Client with certificates</a></li></ul><li><a href="#auto10">Other facilities</a></li><li><a href="#auto11">Conclusion</a></li></ol></div>
+ <div class="content">
+ <span/>
+
+ <h2>Overview<a name="auto0"/></h2>
+
+ <p>This document describes how to use SSL in Twisted servers and clients. It
+ assumes that you know what SSL is, what some of the major reasons to use it
+ are, and how to generate your own SSL certificates, in particular self-signed
+ certificates. It also assumes that you are comfortable with creating TCP
+ servers and clients as described in the <a href="servers.html" shape="rect">server howto
+ </a> and <a href="clients.html" shape="rect">client howto</a>. After reading this
+ document you should be able to create servers and clients that can use SSL to
+ encrypt their connections, switch from using an unencrypted channel to an
+ encrypted one mid-connection, and require client authentication.</p>
+
+ <p>Using SSL in Twisted requires that you have
+ <a href="http://pyopenssl.sf.net" shape="rect">pyOpenSSL</a> installed. A quick test to
+ verify that you do is to run <code>from OpenSSL import SSL</code> at a
+ python prompt and not get an error.</p>
+
+ <p>SSL connections require SSL contexts. These contexts are generated by a
+ <code>ContextFactory</code> that maintains state like the SSL method, private
+ key file name, and certificate file name.</p>
+
+ <p>Instead of using listenTCP and connectTCP to create a connection, use
+ <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.interfaces.IReactorSSL.listenSSL.html" title="twisted.internet.interfaces.IReactorSSL.listenSSL">listenSSL</a></code> and
+ <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.interfaces.IReactorSSL.connectSSL.html" title="twisted.internet.interfaces.IReactorSSL.connectSSL">connectSSL</a></code> for a
+ server and client respectively. These methods take a contextFactory as an
+ additional argument.</p>
+
+ <p>The basic server context factory is
+ <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.ssl.ContextFactory.html" title="twisted.internet.ssl.ContextFactory">twisted.internet.ssl.ContextFactory</a></code>, and the basic
+ client context factory is
+ <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.ssl.ClientContextFactory.html" title="twisted.internet.ssl.ClientContextFactory">twisted.internet.ssl.ClientContextFactory</a></code>. They can
+ be used as-is or subclassed.
+ <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.ssl.DefaultOpenSSLContextFactory.html" title="twisted.internet.ssl.DefaultOpenSSLContextFactory">twisted.internet.ssl.DefaultOpenSSLContextFactory</a></code>
+ is a convenience server class that subclasses <code>ContextFactory</code>
+ and adds default parameters to the SSL handshake and connection. Another
+ useful class is
+ <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.ssl.CertificateOptions.html" title="twisted.internet.ssl.CertificateOptions">twisted.internet.ssl.CertificateOptions</a></code>; it is a
+ factory for SSL context objects that lets you specify many of the common
+ verification and session options so it can do the proper pyOpenSSL
+ initialization for you.</p>
+
+ <p>Those are the big immediate differences between TCP and SSL connections,
+ so let's look at an example. In it and all subsequent examples it is assumed
+ that keys and certificates for the server, certificate authority, and client
+ should they exist live in a <i>keys/</i> subdirectory of the directory
+ containing the example code, and that the certificates are self-signed.</p>
+
+ <h2>SSL echo server and client without client authentication<a name="auto1"/></h2>
+
+ <p>Authentication and encryption are two separate parts of the SSL protocol.
+ The server almost always needs a key and certificate to authenticate itself
+ to the client but is usually configured to allow encrypted connections with
+ unauthenticated clients who don't have certificates. This common case is
+ demonstrated first by adding SSL support to the echo client and server in
+ the <a href="../examples/index.html" shape="rect">core examples</a>.</p>
+
+ <h3>SSL echo server<a name="auto2"/></h3>
+
+ <pre class="python"><p class="py-linenumber"> 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ssl</span>, <span class="py-src-variable">reactor</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Factory</span>, <span class="py-src-variable">Protocol</span>
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">Echo</span>(<span class="py-src-parameter">Protocol</span>):
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">dataReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">data</span>):
+ <span class="py-src-string">&quot;&quot;&quot;As soon as any data is received, write it back.&quot;&quot;&quot;</span>
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">data</span>)
+
+<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
+ <span class="py-src-variable">factory</span> = <span class="py-src-variable">Factory</span>()
+ <span class="py-src-variable">factory</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">Echo</span>
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenSSL</span>(<span class="py-src-number">8000</span>, <span class="py-src-variable">factory</span>,
+ <span class="py-src-variable">ssl</span>.<span class="py-src-variable">DefaultOpenSSLContextFactory</span>(
+ <span class="py-src-string">'keys/server.key'</span>, <span class="py-src-string">'keys/server.crt'</span>))
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
+</pre>
+
+ <h3>SSL echo client<a name="auto3"/></h3>
+
+ <pre class="python"><p class="py-linenumber"> 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ssl</span>, <span class="py-src-variable">reactor</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ClientFactory</span>, <span class="py-src-variable">Protocol</span>
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">EchoClient</span>(<span class="py-src-parameter">Protocol</span>):
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;hello, world&quot;</span>
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">&quot;hello, world!&quot;</span>)
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">dataReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">data</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Server said:&quot;</span>, <span class="py-src-variable">data</span>
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">EchoClientFactory</span>(<span class="py-src-parameter">ClientFactory</span>):
+ <span class="py-src-variable">protocol</span> = <span class="py-src-variable">EchoClient</span>
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">clientConnectionFailed</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">connector</span>, <span class="py-src-parameter">reason</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Connection failed - goodbye!&quot;</span>
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">clientConnectionLost</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">connector</span>, <span class="py-src-parameter">reason</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Connection lost - goodbye!&quot;</span>
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
+
+<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
+ <span class="py-src-variable">factory</span> = <span class="py-src-variable">EchoClientFactory</span>()
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectSSL</span>(<span class="py-src-string">'localhost'</span>, <span class="py-src-number">8000</span>, <span class="py-src-variable">factory</span>, <span class="py-src-variable">ssl</span>.<span class="py-src-variable">ClientContextFactory</span>())
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
+</pre>
+
+ <p>Contexts are created according to a specified method.
+ <code>SSLv3_METHOD</code>, <code>SSLv23_METHOD</code>, and
+ <code>TLSv1_METHOD</code> are the valid constants that represent SSL methods
+ to use when creating a context object. <code>DefaultOpenSSLContextFactory</code> and
+ <code>ClientContextFactory</code> default to using <code>SSL.SSLv23_METHOD</code> as their
+ method, and it is compatible for communication with all the other methods
+ listed above. An older method constant, <code>SSLv2_METHOD</code>, exists but
+ is explicitly disallowed in both <code>DefaultOpenSSLContextFactory</code> and
+ <code>ClientContextFactory</code> for being insecure by calling
+ <code>set_options(SSL.OP_NO_SSLv2)</code> on their contexts. See
+ <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.ssl.html" title="twisted.internet.ssl">twisted.internet.ssl</a></code> for additional comments.</p>
+
+ <h2>Using startTLS<a name="auto4"/></h2>
+
+ <p>If you want to switch from unencrypted to encrypted traffic
+ mid-connection, you'll need to turn on SSL with <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.interfaces.ITLSTransport.startTLS.html" title="twisted.internet.interfaces.ITLSTransport.startTLS">startTLS</a></code> on both
+ ends of the connection at the same time via some agreed-upon signal like the
+ reception of a particular message. You can readily verify the switch to an
+ encrypted channel by examining the packet payloads with a tool like
+ <a href="http://www.wireshark.org/" shape="rect">Wireshark</a>.</p>
+
+ <h3>startTLS server<a name="auto5"/></h3>
+
+ <pre class="python"><p class="py-linenumber"> 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+</p><span class="py-src-keyword">from</span> <span class="py-src-variable">OpenSSL</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">SSL</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>, <span class="py-src-variable">ssl</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ServerFactory</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span>.<span class="py-src-variable">basic</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">LineReceiver</span>
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">TLSServer</span>(<span class="py-src-parameter">LineReceiver</span>):
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">line</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;received: &quot;</span> + <span class="py-src-variable">line</span>
+
+ <span class="py-src-keyword">if</span> <span class="py-src-variable">line</span> == <span class="py-src-string">&quot;STARTTLS&quot;</span>:
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;-- Switching to TLS&quot;</span>
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-string">'READY'</span>)
+ <span class="py-src-variable">ctx</span> = <span class="py-src-variable">ServerTLSContext</span>(
+ <span class="py-src-variable">privateKeyFileName</span>=<span class="py-src-string">'keys/server.key'</span>,
+ <span class="py-src-variable">certificateFileName</span>=<span class="py-src-string">'keys/server.crt'</span>,
+ )
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">startTLS</span>(<span class="py-src-variable">ctx</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">factory</span>)
+
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">ServerTLSContext</span>(<span class="py-src-parameter">ssl</span>.<span class="py-src-parameter">DefaultOpenSSLContextFactory</span>):
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, *<span class="py-src-parameter">args</span>, **<span class="py-src-parameter">kw</span>):
+ <span class="py-src-variable">kw</span>[<span class="py-src-string">'sslmethod'</span>] = <span class="py-src-variable">SSL</span>.<span class="py-src-variable">TLSv1_METHOD</span>
+ <span class="py-src-variable">ssl</span>.<span class="py-src-variable">DefaultOpenSSLContextFactory</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>, *<span class="py-src-variable">args</span>, **<span class="py-src-variable">kw</span>)
+
+<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
+ <span class="py-src-variable">factory</span> = <span class="py-src-variable">ServerFactory</span>()
+ <span class="py-src-variable">factory</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">TLSServer</span>
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8000</span>, <span class="py-src-variable">factory</span>)
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
+</pre>
+
+ <h3>startTLS client<a name="auto6"/></h3>
+
+ <pre class="python"><p class="py-linenumber"> 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+</p><span class="py-src-keyword">from</span> <span class="py-src-variable">OpenSSL</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">SSL</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>, <span class="py-src-variable">ssl</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ClientFactory</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span>.<span class="py-src-variable">basic</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">LineReceiver</span>
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">ClientTLSContext</span>(<span class="py-src-parameter">ssl</span>.<span class="py-src-parameter">ClientContextFactory</span>):
+ <span class="py-src-variable">isClient</span> = <span class="py-src-number">1</span>
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">getContext</span>(<span class="py-src-parameter">self</span>):
+ <span class="py-src-keyword">return</span> <span class="py-src-variable">SSL</span>.<span class="py-src-variable">Context</span>(<span class="py-src-variable">SSL</span>.<span class="py-src-variable">TLSv1_METHOD</span>)
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">TLSClient</span>(<span class="py-src-parameter">LineReceiver</span>):
+ <span class="py-src-variable">pretext</span> = [
+ <span class="py-src-string">&quot;first line&quot;</span>,
+ <span class="py-src-string">&quot;last thing before TLS starts&quot;</span>,
+ <span class="py-src-string">&quot;STARTTLS&quot;</span>]
+
+ <span class="py-src-variable">posttext</span> = [
+ <span class="py-src-string">&quot;first thing after TLS started&quot;</span>,
+ <span class="py-src-string">&quot;last thing ever&quot;</span>]
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
+ <span class="py-src-keyword">for</span> <span class="py-src-variable">l</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">pretext</span>:
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-variable">l</span>)
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">line</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;received: &quot;</span> + <span class="py-src-variable">line</span>
+ <span class="py-src-keyword">if</span> <span class="py-src-variable">line</span> == <span class="py-src-string">&quot;READY&quot;</span>:
+ <span class="py-src-variable">ctx</span> = <span class="py-src-variable">ClientTLSContext</span>()
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">startTLS</span>(<span class="py-src-variable">ctx</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">factory</span>)
+ <span class="py-src-keyword">for</span> <span class="py-src-variable">l</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">posttext</span>:
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-variable">l</span>)
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">TLSClientFactory</span>(<span class="py-src-parameter">ClientFactory</span>):
+ <span class="py-src-variable">protocol</span> = <span class="py-src-variable">TLSClient</span>
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">clientConnectionFailed</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">connector</span>, <span class="py-src-parameter">reason</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;connection failed: &quot;</span>, <span class="py-src-variable">reason</span>.<span class="py-src-variable">getErrorMessage</span>()
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">clientConnectionLost</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">connector</span>, <span class="py-src-parameter">reason</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;connection lost: &quot;</span>, <span class="py-src-variable">reason</span>.<span class="py-src-variable">getErrorMessage</span>()
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
+
+<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">&quot;__main__&quot;</span>:
+ <span class="py-src-variable">factory</span> = <span class="py-src-variable">TLSClientFactory</span>()
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">'localhost'</span>, <span class="py-src-number">8000</span>, <span class="py-src-variable">factory</span>)
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
+</pre>
+
+ <p><code>startTLS</code> is a transport method that gets passed a context.
+ It is invoked at an agreed-upon time in the data reception method of the
+ client and server protocols. The <code>ServerTLSContext</code> and
+ <code>ClientTLSContext</code> classes used above inherit from the basic
+ server and client context factories used in the earlier echo examples and
+ illustrate two more ways of setting an SSL method.</p>
+
+ <h2>Client authentication<a name="auto7"/></h2>
+
+ <p>Server and client-side changes to require client authentication fall
+ largely under the dominion of pyOpenSSL, but few examples seem to exist on
+ the web so for completeness a sample server and client are provided here.</p>
+
+ <h3>Client-authenticating server<a name="auto8"/></h3>
+
+ <pre class="python"><p class="py-linenumber"> 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+</p><span class="py-src-keyword">from</span> <span class="py-src-variable">OpenSSL</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">SSL</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ssl</span>, <span class="py-src-variable">reactor</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Factory</span>, <span class="py-src-variable">Protocol</span>
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">Echo</span>(<span class="py-src-parameter">Protocol</span>):
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">dataReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">data</span>):
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">data</span>)
+
+<span class="py-src-keyword">def</span> <span class="py-src-identifier">verifyCallback</span>(<span class="py-src-parameter">connection</span>, <span class="py-src-parameter">x509</span>, <span class="py-src-parameter">errnum</span>, <span class="py-src-parameter">errdepth</span>, <span class="py-src-parameter">ok</span>):
+ <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">ok</span>:
+ <span class="py-src-keyword">print</span> <span class="py-src-string">'invalid cert from subject:'</span>, <span class="py-src-variable">x509</span>.<span class="py-src-variable">get_subject</span>()
+ <span class="py-src-keyword">return</span> <span class="py-src-variable">False</span>
+ <span class="py-src-keyword">else</span>:
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Certs are fine&quot;</span>
+ <span class="py-src-keyword">return</span> <span class="py-src-variable">True</span>
+
+<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
+ <span class="py-src-variable">factory</span> = <span class="py-src-variable">Factory</span>()
+ <span class="py-src-variable">factory</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">Echo</span>
+
+ <span class="py-src-variable">myContextFactory</span> = <span class="py-src-variable">ssl</span>.<span class="py-src-variable">DefaultOpenSSLContextFactory</span>(
+ <span class="py-src-string">'keys/server.key'</span>, <span class="py-src-string">'keys/server.crt'</span>
+ )
+
+ <span class="py-src-variable">ctx</span> = <span class="py-src-variable">myContextFactory</span>.<span class="py-src-variable">getContext</span>()
+
+ <span class="py-src-variable">ctx</span>.<span class="py-src-variable">set_verify</span>(
+ <span class="py-src-variable">SSL</span>.<span class="py-src-variable">VERIFY_PEER</span> | <span class="py-src-variable">SSL</span>.<span class="py-src-variable">VERIFY_FAIL_IF_NO_PEER_CERT</span>,
+ <span class="py-src-variable">verifyCallback</span>
+ )
+
+ <span class="py-src-comment"># Since we have self-signed certs we have to explicitly</span>
+ <span class="py-src-comment"># tell the server to trust them.</span>
+ <span class="py-src-variable">ctx</span>.<span class="py-src-variable">load_verify_locations</span>(<span class="py-src-string">&quot;keys/ca.pem&quot;</span>)
+
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenSSL</span>(<span class="py-src-number">8000</span>, <span class="py-src-variable">factory</span>, <span class="py-src-variable">myContextFactory</span>)
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
+</pre>
+
+ <p>Use the <code>set_verify</code> method to set the verification mode for a
+ context object and the verification callback. The mode is either
+ <code>VERIFY_NONE</code> or <code>VERIFY_PEER</code>. If
+ <code>VERIFY_PEER</code> is set, the mode can be augmented by
+ <code>VERIFY_FAIL_IF_NO_PEER_CERT</code> and/or
+ <code>VERIFY_CLIENT_ONCE</code>.</p>
+
+ <p>The callback takes as its arguments a connection object, X509 object,
+ error number, error depth, and return code. The purpose of the callback is
+ to allow you to enforce additional restrictions on the verification. Thus,
+ if the return code is False, you should return False; if the return code is
+ True <i>and</i> further verification passes, return True.</p>
+
+
+ <h3>Client with certificates<a name="auto9"/></h3>
+
+ <pre class="python"><p class="py-linenumber"> 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+</p><span class="py-src-keyword">from</span> <span class="py-src-variable">OpenSSL</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">SSL</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ssl</span>, <span class="py-src-variable">reactor</span>
+<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ClientFactory</span>, <span class="py-src-variable">Protocol</span>
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">EchoClient</span>(<span class="py-src-parameter">Protocol</span>):
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;hello, world&quot;</span>
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">&quot;hello, world!&quot;</span>)
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">dataReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">data</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Server said:&quot;</span>, <span class="py-src-variable">data</span>
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">EchoClientFactory</span>(<span class="py-src-parameter">ClientFactory</span>):
+ <span class="py-src-variable">protocol</span> = <span class="py-src-variable">EchoClient</span>
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">clientConnectionFailed</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">connector</span>, <span class="py-src-parameter">reason</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Connection failed - goodbye!&quot;</span>
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
+
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">clientConnectionLost</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">connector</span>, <span class="py-src-parameter">reason</span>):
+ <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Connection lost - goodbye!&quot;</span>
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
+
+<span class="py-src-keyword">class</span> <span class="py-src-identifier">CtxFactory</span>(<span class="py-src-parameter">ssl</span>.<span class="py-src-parameter">ClientContextFactory</span>):
+ <span class="py-src-keyword">def</span> <span class="py-src-identifier">getContext</span>(<span class="py-src-parameter">self</span>):
+ <span class="py-src-variable">self</span>.<span class="py-src-variable">method</span> = <span class="py-src-variable">SSL</span>.<span class="py-src-variable">SSLv23_METHOD</span>
+ <span class="py-src-variable">ctx</span> = <span class="py-src-variable">ssl</span>.<span class="py-src-variable">ClientContextFactory</span>.<span class="py-src-variable">getContext</span>(<span class="py-src-variable">self</span>)
+ <span class="py-src-variable">ctx</span>.<span class="py-src-variable">use_certificate_file</span>(<span class="py-src-string">'keys/client.crt'</span>)
+ <span class="py-src-variable">ctx</span>.<span class="py-src-variable">use_privatekey_file</span>(<span class="py-src-string">'keys/client.key'</span>)
+
+ <span class="py-src-keyword">return</span> <span class="py-src-variable">ctx</span>
+
+<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
+ <span class="py-src-variable">factory</span> = <span class="py-src-variable">EchoClientFactory</span>()
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectSSL</span>(<span class="py-src-string">'localhost'</span>, <span class="py-src-number">8000</span>, <span class="py-src-variable">factory</span>, <span class="py-src-variable">CtxFactory</span>())
+ <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
+</pre>
+
+ <h2>Other facilities<a name="auto10"/></h2>
+
+ <p><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.protocols.amp.html" title="twisted.protocols.amp">twisted.protocols.amp</a></code> supports encrypted
+ connections and exposes a <code>startTLS</code> method one can use or
+ subclass. <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.html" title="twisted.web">twisted.web</a></code> has built-in SSL support in
+ its <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.client.html" title="twisted.web.client">client</a></code>, <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.http.html" title="twisted.web.http">http</a></code>, and <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.xmlrpc.html" title="twisted.web.xmlrpc">xmlrpc</a></code> modules.</p>
+
+ <h2>Conclusion<a name="auto11"/></h2>
+
+ <p>After reading through this tutorial, you should be able to: </p>
+ <ul>
+ <li>Use <code>listenSSL</code> and <code>connectSSL</code> to create servers and clients that use
+ SSL</li>
+ <li>Use <code>startTLS</code> to switch a channel from being unencrypted to using SSL
+ mid-connection</li>
+ <li>Add server and client support for client authentication</li>
+ </ul>
+
+ </div>
+
+ <p><a href="index.html">Index</a></p>
+ <span class="version">Version: 12.1.0</span>
+ </body>
+</html> \ No newline at end of file