1
# -*- test-case-name: twisted.test.test_ssl -*-
2
# Copyright (c) 2001-2009 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
20
- support for switching TCP into SSL
23
Maintainer: Itamar Shtull-Trauring
26
# If something goes wrong, most notably an OpenSSL import failure,
27
# sys.modules['twisted.internet.ssl'] will be bound to a partially
28
# initialized module object. This is wacko, but we will take advantage
29
# of it to publish whether or not SSL is available.
30
# See the end of this module for the other half of this solution.
32
# The correct idiom to import this module is thus:
35
# from twisted.internet import ssl
37
# # happens the first time the interpreter tries to import it
39
# if ssl and not ssl.supported:
40
# # happens second and later times
46
from OpenSSL import SSL
47
from zope.interface import implements, implementsOnly, implementedBy
50
from twisted.internet import tcp, interfaces, base, address
54
"""A factory for SSL context objects, for server SSL connections."""
59
"""Return a SSL.Context object. override in subclasses."""
60
raise NotImplementedError
63
class DefaultOpenSSLContextFactory(ContextFactory):
65
L{DefaultOpenSSLContextFactory} is a factory for server-side SSL context
66
objects. These objects define certain parameters related to SSL
67
handshakes and the subsequent connection.
69
@ivar _contextFactory: A callable which will be used to create new
70
context objects. This is typically L{SSL.Context}.
74
def __init__(self, privateKeyFileName, certificateFileName,
75
sslmethod=SSL.SSLv23_METHOD, _contextFactory=SSL.Context):
77
@param privateKeyFileName: Name of a file containing a private key
78
@param certificateFileName: Name of a file containing a certificate
79
@param sslmethod: The SSL method to use
81
self.privateKeyFileName = privateKeyFileName
82
self.certificateFileName = certificateFileName
83
self.sslmethod = sslmethod
84
self._contextFactory = _contextFactory
86
# Create a context object right now. This is to force validation of
87
# the given parameters so that errors are detected earlier rather
92
def cacheContext(self):
93
if self._context is None:
94
ctx = self._contextFactory(self.sslmethod)
95
# Disallow SSLv2! It's insecure! SSLv3 has been around since
96
# 1996. It's time to move on.
97
ctx.set_options(SSL.OP_NO_SSLv2)
98
ctx.use_certificate_file(self.certificateFileName)
99
ctx.use_privatekey_file(self.privateKeyFileName)
103
def __getstate__(self):
104
d = self.__dict__.copy()
109
def __setstate__(self, state):
110
self.__dict__ = state
113
def getContext(self):
115
Return an SSL context.
120
class ClientContextFactory:
121
"""A context factory for SSL clients."""
125
# SSLv23_METHOD allows SSLv2, SSLv3, and TLSv1. We disable SSLv2 below,
127
method = SSL.SSLv23_METHOD
129
_contextFactory = SSL.Context
131
def getContext(self):
132
ctx = self._contextFactory(self.method)
133
# See comment in DefaultOpenSSLContextFactory about SSLv2.
134
ctx.set_options(SSL.OP_NO_SSLv2)
139
class Client(tcp.Client):
140
"""I am an SSL client."""
142
implementsOnly(interfaces.ISSLTransport,
143
*[i for i in implementedBy(tcp.Client) if i != interfaces.ITLSTransport])
145
def __init__(self, host, port, bindAddress, ctxFactory, connector, reactor=None):
146
# tcp.Client.__init__ depends on self.ctxFactory being set
147
self.ctxFactory = ctxFactory
148
tcp.Client.__init__(self, host, port, bindAddress, connector, reactor)
151
"""Returns the address from which I am connecting."""
152
h, p = self.socket.getsockname()
153
return address.IPv4Address('TCP', h, p, 'SSL')
156
"""Returns the address that I am connected."""
157
return address.IPv4Address('TCP', self.addr[0], self.addr[1], 'SSL')
159
def _connectDone(self):
160
self.startTLS(self.ctxFactory)
162
tcp.Client._connectDone(self)
165
class Server(tcp.Server):
166
"""I am an SSL server.
169
implements(interfaces.ISSLTransport)
172
"""Return server's address."""
173
h, p = self.socket.getsockname()
174
return address.IPv4Address('TCP', h, p, 'SSL')
177
"""Return address of peer."""
179
return address.IPv4Address('TCP', h, p, 'SSL')
182
class Port(tcp.Port):
183
"""I am an SSL port."""
184
_socketShutdownMethod = 'sock_shutdown'
188
def __init__(self, port, factory, ctxFactory, backlog=50, interface='', reactor=None):
189
tcp.Port.__init__(self, port, factory, backlog, interface, reactor)
190
self.ctxFactory = ctxFactory
192
def createInternetSocket(self):
193
"""(internal) create an SSL socket
195
sock = tcp.Port.createInternetSocket(self)
196
return SSL.Connection(self.ctxFactory.getContext(), sock)
198
def _preMakeConnection(self, transport):
199
# *Don't* call startTLS here
200
# The transport already has the SSL.Connection object from above
201
transport._startTLS()
202
return tcp.Port._preMakeConnection(self, transport)
205
class Connector(base.BaseConnector):
206
def __init__(self, host, port, factory, contextFactory, timeout, bindAddress, reactor=None):
209
self.bindAddress = bindAddress
210
self.contextFactory = contextFactory
211
base.BaseConnector.__init__(self, factory, timeout, reactor)
213
def _makeTransport(self):
214
return Client(self.host, self.port, self.bindAddress, self.contextFactory, self, self.reactor)
216
def getDestination(self):
217
return address.IPv4Address('TCP', self.host, self.port, 'SSL')
219
from twisted.internet._sslverify import DistinguishedName, DN, Certificate
220
from twisted.internet._sslverify import CertificateRequest, PrivateCertificate
221
from twisted.internet._sslverify import KeyPair
222
from twisted.internet._sslverify import OpenSSLCertificateOptions as CertificateOptions
225
"ContextFactory", "DefaultOpenSSLContextFactory", "ClientContextFactory",
227
'DistinguishedName', 'DN',
228
'Certificate', 'CertificateRequest', 'PrivateCertificate',
230
'CertificateOptions',