Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / internet / ssl.py
1 # -*- test-case-name: twisted.test.test_ssl -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5
6 """
7 SSL transport. Requires PyOpenSSL (http://pyopenssl.sf.net).
8
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
12 in IReactorSSL.
13
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.
17
18 Future Plans:
19     - split module so reactor-specific classes are in a separate module
20 """
21
22 # System imports
23 from OpenSSL import SSL
24 supported = True
25
26 from zope.interface import implements, implementsOnly, implementedBy
27
28 # Twisted imports
29 from twisted.internet import tcp, interfaces
30
31
32 class ContextFactory:
33     """A factory for SSL context objects, for server SSL connections."""
34
35     isClient = 0
36
37     def getContext(self):
38         """Return a SSL.Context object. override in subclasses."""
39         raise NotImplementedError
40
41
42 class DefaultOpenSSLContextFactory(ContextFactory):
43     """
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.
47
48     @ivar _contextFactory: A callable which will be used to create new
49         context objects.  This is typically L{SSL.Context}.
50     """
51     _context = None
52
53     def __init__(self, privateKeyFileName, certificateFileName,
54                  sslmethod=SSL.SSLv23_METHOD, _contextFactory=SSL.Context):
55         """
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
59         """
60         self.privateKeyFileName = privateKeyFileName
61         self.certificateFileName = certificateFileName
62         self.sslmethod = sslmethod
63         self._contextFactory = _contextFactory
64
65         # Create a context object right now.  This is to force validation of
66         # the given parameters so that errors are detected earlier rather
67         # than later.
68         self.cacheContext()
69
70
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)
79             self._context = ctx
80
81
82     def __getstate__(self):
83         d = self.__dict__.copy()
84         del d['_context']
85         return d
86
87
88     def __setstate__(self, state):
89         self.__dict__ = state
90
91
92     def getContext(self):
93         """
94         Return an SSL context.
95         """
96         return self._context
97
98
99 class ClientContextFactory:
100     """A context factory for SSL clients."""
101
102     isClient = 1
103
104     # SSLv23_METHOD allows SSLv2, SSLv3, and TLSv1.  We disable SSLv2 below,
105     # though.
106     method = SSL.SSLv23_METHOD
107
108     _contextFactory = SSL.Context
109
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)
114         return ctx
115
116
117
118 class Client(tcp.Client):
119     """
120     I am an SSL client.
121     """
122
123     implementsOnly(interfaces.ISSLTransport,
124                    *[i for i in implementedBy(tcp.Client) if i != interfaces.ITLSTransport])
125
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)
130
131     def _connectDone(self):
132         self.startTLS(self.ctxFactory)
133         self.startWriting()
134         tcp.Client._connectDone(self)
135
136
137
138 class Server(tcp.Server):
139     """
140     I am an SSL server.
141     """
142     implements(interfaces.ISSLTransport)
143
144     def __init__(self, *args, **kwargs):
145         tcp.Server.__init__(self, *args, **kwargs)
146         self.startTLS(self.server.ctxFactory)
147
148
149
150 class Port(tcp.Port):
151     """
152     I am an SSL port.
153     """
154     transport = Server
155
156     _type = 'TLS'
157
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
161
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()
165
166
167     def _getLogPrefix(self, factory):
168         """
169         Override the normal prefix to include an annotation indicating this is a
170         port for TLS connections.
171         """
172         return tcp.Port._getLogPrefix(self, factory) + ' (TLS)'
173
174
175
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)
180
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()
184
185
186     def _makeTransport(self):
187         return Client(self.host, self.port, self.bindAddress, self.contextFactory, self, self.reactor)
188
189
190
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
195
196 __all__ = [
197     "ContextFactory", "DefaultOpenSSLContextFactory", "ClientContextFactory",
198
199     'DistinguishedName', 'DN',
200     'Certificate', 'CertificateRequest', 'PrivateCertificate',
201     'KeyPair',
202     'CertificateOptions',
203     ]