ssl.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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 annotations
  44. from zope.interface import implementedBy, implementer, implementer_only
  45. # System imports
  46. from OpenSSL import SSL
  47. # Twisted imports
  48. from twisted.internet import interfaces, tcp
  49. supported = True
  50. @implementer(interfaces.IOpenSSLContextFactory)
  51. class ContextFactory:
  52. """A factory for SSL context objects, for server SSL connections."""
  53. isClient = 0
  54. def getContext(self):
  55. """Return a SSL.Context object. override in subclasses."""
  56. raise NotImplementedError
  57. class DefaultOpenSSLContextFactory(ContextFactory):
  58. """
  59. L{DefaultOpenSSLContextFactory} is a factory for server-side SSL context
  60. objects. These objects define certain parameters related to SSL
  61. handshakes and the subsequent connection.
  62. @ivar _contextFactory: A callable which will be used to create new
  63. context objects. This is typically L{OpenSSL.SSL.Context}.
  64. """
  65. _context = None
  66. def __init__(
  67. self,
  68. privateKeyFileName,
  69. certificateFileName,
  70. sslmethod=SSL.TLS_METHOD,
  71. _contextFactory=SSL.Context,
  72. ):
  73. """
  74. @param privateKeyFileName: Name of a file containing a private key
  75. @param certificateFileName: Name of a file containing a certificate
  76. @param sslmethod: The SSL method to use
  77. """
  78. self.privateKeyFileName = privateKeyFileName
  79. self.certificateFileName = certificateFileName
  80. self.sslmethod = sslmethod
  81. self._contextFactory = _contextFactory
  82. # Create a context object right now. This is to force validation of
  83. # the given parameters so that errors are detected earlier rather
  84. # than later.
  85. self.cacheContext()
  86. def cacheContext(self):
  87. if self._context is None:
  88. ctx = self._contextFactory(self.sslmethod)
  89. # Disallow SSLv2! It's insecure! SSLv3 has been around since
  90. # 1996. It's time to move on.
  91. ctx.set_options(SSL.OP_NO_SSLv2)
  92. ctx.use_certificate_file(self.certificateFileName)
  93. ctx.use_privatekey_file(self.privateKeyFileName)
  94. self._context = ctx
  95. def __getstate__(self):
  96. d = self.__dict__.copy()
  97. del d["_context"]
  98. return d
  99. def __setstate__(self, state):
  100. self.__dict__ = state
  101. def getContext(self):
  102. """
  103. Return an SSL context.
  104. """
  105. return self._context
  106. @implementer(interfaces.IOpenSSLContextFactory)
  107. class ClientContextFactory:
  108. """A context factory for SSL clients."""
  109. isClient = 1
  110. # TLS_METHOD allows negotiation of multiple TLS versions.
  111. method = SSL.TLS_METHOD
  112. _contextFactory = SSL.Context
  113. def getContext(self):
  114. ctx = self._contextFactory(self.method)
  115. ctx.set_options(
  116. SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3 | SSL.OP_NO_TLSv1 | SSL.OP_NO_TLSv1_1
  117. )
  118. return ctx
  119. @implementer_only(
  120. interfaces.ISSLTransport,
  121. *(i for i in implementedBy(tcp.Client) if i != interfaces.ITLSTransport),
  122. )
  123. class Client(tcp.Client):
  124. """
  125. I am an SSL client.
  126. """
  127. def __init__(self, host, port, bindAddress, ctxFactory, connector, reactor=None):
  128. # tcp.Client.__init__ depends on self.ctxFactory being set
  129. self.ctxFactory = ctxFactory
  130. tcp.Client.__init__(self, host, port, bindAddress, connector, reactor)
  131. def _connectDone(self):
  132. self.startTLS(self.ctxFactory)
  133. self.startWriting()
  134. tcp.Client._connectDone(self)
  135. @implementer(interfaces.ISSLTransport)
  136. class Server(tcp.Server):
  137. """
  138. I am an SSL server.
  139. """
  140. server: Port
  141. def __init__(self, *args, **kwargs):
  142. tcp.Server.__init__(self, *args, **kwargs)
  143. self.startTLS(self.server.ctxFactory)
  144. def getPeerCertificate(self):
  145. # ISSLTransport.getPeerCertificate
  146. raise NotImplementedError("Server.getPeerCertificate")
  147. class Port(tcp.Port):
  148. """
  149. I am an SSL port.
  150. """
  151. transport = Server
  152. _type = "TLS"
  153. def __init__(
  154. self, port, factory, ctxFactory, backlog=50, interface="", reactor=None
  155. ):
  156. tcp.Port.__init__(self, port, factory, backlog, interface, reactor)
  157. self.ctxFactory = ctxFactory
  158. def _getLogPrefix(self, factory):
  159. """
  160. Override the normal prefix to include an annotation indicating this is a
  161. port for TLS connections.
  162. """
  163. return tcp.Port._getLogPrefix(self, factory) + " (TLS)"
  164. class Connector(tcp.Connector):
  165. def __init__(
  166. self, host, port, factory, contextFactory, timeout, bindAddress, reactor=None
  167. ):
  168. self.contextFactory = contextFactory
  169. tcp.Connector.__init__(self, host, port, factory, timeout, bindAddress, reactor)
  170. # Force some parameter checking in pyOpenSSL. It's better to fail now
  171. # than after we've set up the transport.
  172. contextFactory.getContext()
  173. def _makeTransport(self):
  174. return Client(
  175. self.host,
  176. self.port,
  177. self.bindAddress,
  178. self.contextFactory,
  179. self,
  180. self.reactor,
  181. )
  182. from twisted.internet._sslverify import (
  183. DN,
  184. Certificate,
  185. CertificateRequest,
  186. DistinguishedName,
  187. KeyPair,
  188. OpenSSLAcceptableCiphers as AcceptableCiphers,
  189. OpenSSLCertificateOptions as CertificateOptions,
  190. OpenSSLDefaultPaths,
  191. OpenSSLDiffieHellmanParameters as DiffieHellmanParameters,
  192. PrivateCertificate,
  193. ProtocolNegotiationSupport,
  194. TLSVersion,
  195. VerificationError,
  196. optionsForClientTLS,
  197. platformTrust,
  198. protocolNegotiationMechanisms,
  199. trustRootFromCertificates,
  200. )
  201. __all__ = [
  202. "ContextFactory",
  203. "DefaultOpenSSLContextFactory",
  204. "ClientContextFactory",
  205. "DistinguishedName",
  206. "DN",
  207. "Certificate",
  208. "CertificateRequest",
  209. "PrivateCertificate",
  210. "KeyPair",
  211. "AcceptableCiphers",
  212. "CertificateOptions",
  213. "DiffieHellmanParameters",
  214. "platformTrust",
  215. "OpenSSLDefaultPaths",
  216. "TLSVersion",
  217. "VerificationError",
  218. "optionsForClientTLS",
  219. "ProtocolNegotiationSupport",
  220. "protocolNegotiationMechanisms",
  221. "trustRootFromCertificates",
  222. ]