1 # -*- test-case-name: twisted.test.test_ssl -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
7 SSL transport. Requires PyOpenSSL (http://pyopenssl.sf.net).
9 SSL connections require a ContextFactory so they can create SSL contexts.
10 End users should only use the ContextFactory classes directly - for SSL
11 connections use the reactor.connectSSL/listenSSL and so on, as documented
14 All server context factories should inherit from ContextFactory, and all
15 client context factories should inherit from ClientContextFactory. At the
16 moment this is not enforced, but in the future it might be.
19 - split module so reactor-specific classes are in a separate module
23 from OpenSSL import SSL
26 from zope.interface import implements, implementsOnly, implementedBy
29 from twisted.internet import tcp, interfaces
33 """A factory for SSL context objects, for server SSL connections."""
38 """Return a SSL.Context object. override in subclasses."""
39 raise NotImplementedError
42 class DefaultOpenSSLContextFactory(ContextFactory):
44 L{DefaultOpenSSLContextFactory} is a factory for server-side SSL context
45 objects. These objects define certain parameters related to SSL
46 handshakes and the subsequent connection.
48 @ivar _contextFactory: A callable which will be used to create new
49 context objects. This is typically L{SSL.Context}.
53 def __init__(self, privateKeyFileName, certificateFileName,
54 sslmethod=SSL.SSLv23_METHOD, _contextFactory=SSL.Context):
56 @param privateKeyFileName: Name of a file containing a private key
57 @param certificateFileName: Name of a file containing a certificate
58 @param sslmethod: The SSL method to use
60 self.privateKeyFileName = privateKeyFileName
61 self.certificateFileName = certificateFileName
62 self.sslmethod = sslmethod
63 self._contextFactory = _contextFactory
65 # Create a context object right now. This is to force validation of
66 # the given parameters so that errors are detected earlier rather
71 def cacheContext(self):
72 if self._context is None:
73 ctx = self._contextFactory(self.sslmethod)
74 # Disallow SSLv2! It's insecure! SSLv3 has been around since
75 # 1996. It's time to move on.
76 ctx.set_options(SSL.OP_NO_SSLv2)
77 ctx.use_certificate_file(self.certificateFileName)
78 ctx.use_privatekey_file(self.privateKeyFileName)
82 def __getstate__(self):
83 d = self.__dict__.copy()
88 def __setstate__(self, state):
94 Return an SSL context.
99 class ClientContextFactory:
100 """A context factory for SSL clients."""
104 # SSLv23_METHOD allows SSLv2, SSLv3, and TLSv1. We disable SSLv2 below,
106 method = SSL.SSLv23_METHOD
108 _contextFactory = SSL.Context
110 def getContext(self):
111 ctx = self._contextFactory(self.method)
112 # See comment in DefaultOpenSSLContextFactory about SSLv2.
113 ctx.set_options(SSL.OP_NO_SSLv2)
118 class Client(tcp.Client):
123 implementsOnly(interfaces.ISSLTransport,
124 *[i for i in implementedBy(tcp.Client) if i != interfaces.ITLSTransport])
126 def __init__(self, host, port, bindAddress, ctxFactory, connector, reactor=None):
127 # tcp.Client.__init__ depends on self.ctxFactory being set
128 self.ctxFactory = ctxFactory
129 tcp.Client.__init__(self, host, port, bindAddress, connector, reactor)
131 def _connectDone(self):
132 self.startTLS(self.ctxFactory)
134 tcp.Client._connectDone(self)
138 class Server(tcp.Server):
142 implements(interfaces.ISSLTransport)
144 def __init__(self, *args, **kwargs):
145 tcp.Server.__init__(self, *args, **kwargs)
146 self.startTLS(self.server.ctxFactory)
150 class Port(tcp.Port):
158 def __init__(self, port, factory, ctxFactory, backlog=50, interface='', reactor=None):
159 tcp.Port.__init__(self, port, factory, backlog, interface, reactor)
160 self.ctxFactory = ctxFactory
162 # Force some parameter checking in pyOpenSSL. It's better to fail now
163 # than after we've set up the transport.
164 ctxFactory.getContext()
167 def _getLogPrefix(self, factory):
169 Override the normal prefix to include an annotation indicating this is a
170 port for TLS connections.
172 return tcp.Port._getLogPrefix(self, factory) + ' (TLS)'
176 class Connector(tcp.Connector):
177 def __init__(self, host, port, factory, contextFactory, timeout, bindAddress, reactor=None):
178 self.contextFactory = contextFactory
179 tcp.Connector.__init__(self, host, port, factory, timeout, bindAddress, reactor)
181 # Force some parameter checking in pyOpenSSL. It's better to fail now
182 # than after we've set up the transport.
183 contextFactory.getContext()
186 def _makeTransport(self):
187 return Client(self.host, self.port, self.bindAddress, self.contextFactory, self, self.reactor)
191 from twisted.internet._sslverify import DistinguishedName, DN, Certificate
192 from twisted.internet._sslverify import CertificateRequest, PrivateCertificate
193 from twisted.internet._sslverify import KeyPair
194 from twisted.internet._sslverify import OpenSSLCertificateOptions as CertificateOptions
197 "ContextFactory", "DefaultOpenSSLContextFactory", "ClientContextFactory",
199 'DistinguishedName', 'DN',
200 'Certificate', 'CertificateRequest', 'PrivateCertificate',
202 'CertificateOptions',