ssl.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. # -*- test-case-name: twisted.test.test_ssl -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. This module implements Transport Layer Security (TLS) support for Twisted. It
  6. requires U{PyOpenSSL <https://pypi.python.org/pypi/pyOpenSSL>}.
  7. If you wish to establish a TLS connection, please use one of the following
  8. APIs:
  9. - SSL endpoints for L{servers
  10. <twisted.internet.endpoints.SSL4ServerEndpoint>} and L{clients
  11. <twisted.internet.endpoints.SSL4ClientEndpoint>}
  12. - L{startTLS <twisted.internet.interfaces.ITLSTransport.startTLS>}
  13. - L{connectSSL <twisted.internet.interfaces.IReactorSSL.connectSSL>}
  14. - L{listenSSL <twisted.internet.interfaces.IReactorSSL.listenSSL>}
  15. These APIs all require a C{contextFactory} argument that specifies their
  16. security properties, such as certificate, private key, certificate authorities
  17. to verify the peer, allowed TLS protocol versions, cipher suites, and so on.
  18. The recommended value for this argument is a L{CertificateOptions} instance;
  19. see its documentation for an explanation of the available options.
  20. The C{contextFactory} name is a bit of an anachronism now, as context factories
  21. have been replaced with "connection creators", but these objects serve the same
  22. role.
  23. Be warned that implementing your own connection creator (i.e.: value for the
  24. C{contextFactory}) is both difficult and dangerous; the Twisted team has worked
  25. hard to make L{CertificateOptions}' API comprehensible and unsurprising, and
  26. the Twisted team is actively maintaining it to ensure that it becomes more
  27. secure over time.
  28. If you are really absolutely sure that you want to take on the risk of
  29. implementing your own connection creator based on the pyOpenSSL API, see the
  30. L{server connection creator
  31. <twisted.internet.interfaces.IOpenSSLServerConnectionCreator>} and L{client
  32. connection creator
  33. <twisted.internet.interfaces.IOpenSSLServerConnectionCreator>} interfaces.
  34. Developers using Twisted, please ignore the L{Port}, L{Connector}, and
  35. L{Client} classes defined here, as these are details of certain reactors' TLS
  36. implementations, exposed by accident (and remaining here only for compatibility
  37. reasons). If you wish to establish a TLS connection, please use one of the
  38. APIs listed above.
  39. @note: "SSL" (Secure Sockets Layer) is an antiquated synonym for "TLS"
  40. (Transport Layer Security). You may see these terms used interchangeably
  41. throughout the documentation.
  42. """
  43. from __future__ import division, absolute_import
  44. # System imports
  45. from OpenSSL import SSL
  46. supported = True
  47. from zope.interface import implementer, implementer_only, implementedBy
  48. # Twisted imports
  49. from twisted.internet import tcp, interfaces
  50. from twisted.python._oldstyle import _oldStyle
  51. @implementer(interfaces.IOpenSSLContextFactory)
  52. @_oldStyle
  53. class ContextFactory:
  54. """A factory for SSL context objects, for server SSL connections."""
  55. isClient = 0
  56. def getContext(self):
  57. """Return a SSL.Context object. override in subclasses."""
  58. raise NotImplementedError
  59. class DefaultOpenSSLContextFactory(ContextFactory):
  60. """
  61. L{DefaultOpenSSLContextFactory} is a factory for server-side SSL context
  62. objects. These objects define certain parameters related to SSL
  63. handshakes and the subsequent connection.
  64. @ivar _contextFactory: A callable which will be used to create new
  65. context objects. This is typically L{OpenSSL.SSL.Context}.
  66. """
  67. _context = None
  68. def __init__(self, privateKeyFileName, certificateFileName,
  69. sslmethod=SSL.SSLv23_METHOD, _contextFactory=SSL.Context):
  70. """
  71. @param privateKeyFileName: Name of a file containing a private key
  72. @param certificateFileName: Name of a file containing a certificate
  73. @param sslmethod: The SSL method to use
  74. """
  75. self.privateKeyFileName = privateKeyFileName
  76. self.certificateFileName = certificateFileName
  77. self.sslmethod = sslmethod
  78. self._contextFactory = _contextFactory
  79. # Create a context object right now. This is to force validation of
  80. # the given parameters so that errors are detected earlier rather
  81. # than later.
  82. self.cacheContext()
  83. def cacheContext(self):
  84. if self._context is None:
  85. ctx = self._contextFactory(self.sslmethod)
  86. # Disallow SSLv2! It's insecure! SSLv3 has been around since
  87. # 1996. It's time to move on.
  88. ctx.set_options(SSL.OP_NO_SSLv2)
  89. ctx.use_certificate_file(self.certificateFileName)
  90. ctx.use_privatekey_file(self.privateKeyFileName)
  91. self._context = ctx
  92. def __getstate__(self):
  93. d = self.__dict__.copy()
  94. del d['_context']
  95. return d
  96. def __setstate__(self, state):
  97. self.__dict__ = state
  98. def getContext(self):
  99. """
  100. Return an SSL context.
  101. """
  102. return self._context
  103. @implementer(interfaces.IOpenSSLContextFactory)
  104. @_oldStyle
  105. class ClientContextFactory:
  106. """A context factory for SSL clients."""
  107. isClient = 1
  108. # SSLv23_METHOD allows SSLv2, SSLv3, and TLSv1. We disable SSLv2 below,
  109. # though.
  110. method = SSL.SSLv23_METHOD
  111. _contextFactory = SSL.Context
  112. def getContext(self):
  113. ctx = self._contextFactory(self.method)
  114. # See comment in DefaultOpenSSLContextFactory about SSLv2.
  115. ctx.set_options(SSL.OP_NO_SSLv2)
  116. return ctx
  117. @implementer_only(interfaces.ISSLTransport,
  118. *[i for i in implementedBy(tcp.Client)
  119. if i != interfaces.ITLSTransport])
  120. class Client(tcp.Client):
  121. """
  122. I am an SSL client.
  123. """
  124. def __init__(self, host, port, bindAddress, ctxFactory, connector, reactor=None):
  125. # tcp.Client.__init__ depends on self.ctxFactory being set
  126. self.ctxFactory = ctxFactory
  127. tcp.Client.__init__(self, host, port, bindAddress, connector, reactor)
  128. def _connectDone(self):
  129. self.startTLS(self.ctxFactory)
  130. self.startWriting()
  131. tcp.Client._connectDone(self)
  132. @implementer(interfaces.ISSLTransport)
  133. class Server(tcp.Server):
  134. """
  135. I am an SSL server.
  136. """
  137. def __init__(self, *args, **kwargs):
  138. tcp.Server.__init__(self, *args, **kwargs)
  139. self.startTLS(self.server.ctxFactory)
  140. class Port(tcp.Port):
  141. """
  142. I am an SSL port.
  143. """
  144. transport = Server
  145. _type = 'TLS'
  146. def __init__(self, port, factory, ctxFactory, backlog=50, interface='', reactor=None):
  147. tcp.Port.__init__(self, port, factory, backlog, interface, reactor)
  148. self.ctxFactory = ctxFactory
  149. def _getLogPrefix(self, factory):
  150. """
  151. Override the normal prefix to include an annotation indicating this is a
  152. port for TLS connections.
  153. """
  154. return tcp.Port._getLogPrefix(self, factory) + ' (TLS)'
  155. class Connector(tcp.Connector):
  156. def __init__(self, host, port, factory, contextFactory, timeout, bindAddress, reactor=None):
  157. self.contextFactory = contextFactory
  158. tcp.Connector.__init__(self, host, port, factory, timeout, bindAddress, reactor)
  159. # Force some parameter checking in pyOpenSSL. It's better to fail now
  160. # than after we've set up the transport.
  161. contextFactory.getContext()
  162. def _makeTransport(self):
  163. return Client(self.host, self.port, self.bindAddress, self.contextFactory, self, self.reactor)
  164. from twisted.internet._sslverify import (
  165. KeyPair, DistinguishedName, DN, Certificate,
  166. CertificateRequest, PrivateCertificate,
  167. OpenSSLAcceptableCiphers as AcceptableCiphers,
  168. OpenSSLCertificateOptions as CertificateOptions,
  169. OpenSSLDiffieHellmanParameters as DiffieHellmanParameters,
  170. platformTrust, OpenSSLDefaultPaths, VerificationError,
  171. optionsForClientTLS, ProtocolNegotiationSupport,
  172. protocolNegotiationMechanisms,
  173. trustRootFromCertificates,
  174. TLSVersion,
  175. )
  176. __all__ = [
  177. "ContextFactory", "DefaultOpenSSLContextFactory", "ClientContextFactory",
  178. 'DistinguishedName', 'DN',
  179. 'Certificate', 'CertificateRequest', 'PrivateCertificate',
  180. 'KeyPair',
  181. 'AcceptableCiphers', 'CertificateOptions', 'DiffieHellmanParameters',
  182. 'platformTrust', 'OpenSSLDefaultPaths', 'TLSVersion',
  183. 'VerificationError', 'optionsForClientTLS',
  184. 'ProtocolNegotiationSupport', 'protocolNegotiationMechanisms',
  185. 'trustRootFromCertificates',
  186. ]