tls.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. # -*- test-case-name: twisted.protocols.test.test_tls,twisted.internet.test.test_tls,twisted.test.test_sslverify -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Implementation of a TLS transport (L{ISSLTransport}) as an
  6. L{IProtocol<twisted.internet.interfaces.IProtocol>} layered on top of any
  7. L{ITransport<twisted.internet.interfaces.ITransport>} implementation, based on
  8. U{OpenSSL<http://www.openssl.org>}'s memory BIO features.
  9. L{TLSMemoryBIOFactory} is a L{WrappingFactory} which wraps protocols created by
  10. the factory it wraps with L{TLSMemoryBIOProtocol}. L{TLSMemoryBIOProtocol}
  11. intercedes between the underlying transport and the wrapped protocol to
  12. implement SSL and TLS. Typical usage of this module looks like this::
  13. from twisted.protocols.tls import TLSMemoryBIOFactory
  14. from twisted.internet.protocol import ServerFactory
  15. from twisted.internet.ssl import PrivateCertificate
  16. from twisted.internet import reactor
  17. from someapplication import ApplicationProtocol
  18. serverFactory = ServerFactory()
  19. serverFactory.protocol = ApplicationProtocol
  20. certificate = PrivateCertificate.loadPEM(certPEMData)
  21. contextFactory = certificate.options()
  22. tlsFactory = TLSMemoryBIOFactory(contextFactory, False, serverFactory)
  23. reactor.listenTCP(12345, tlsFactory)
  24. reactor.run()
  25. This API offers somewhat more flexibility than
  26. L{twisted.internet.interfaces.IReactorSSL}; for example, a
  27. L{TLSMemoryBIOProtocol} instance can use another instance of
  28. L{TLSMemoryBIOProtocol} as its transport, yielding TLS over TLS - useful to
  29. implement onion routing. It can also be used to run TLS over unusual
  30. transports, such as UNIX sockets and stdio.
  31. """
  32. from __future__ import division, absolute_import
  33. from OpenSSL.SSL import Error, ZeroReturnError, WantReadError
  34. from OpenSSL.SSL import TLSv1_METHOD, Context, Connection
  35. try:
  36. Connection(Context(TLSv1_METHOD), None)
  37. except TypeError as e:
  38. if str(e) != "argument must be an int, or have a fileno() method.":
  39. raise
  40. raise ImportError("twisted.protocols.tls requires pyOpenSSL 0.10 or newer.")
  41. from zope.interface import implementer, providedBy, directlyProvides
  42. from twisted.python.compat import unicode
  43. from twisted.python.failure import Failure
  44. from twisted.internet.interfaces import (
  45. ISystemHandle, INegotiated, IPushProducer, ILoggingContext,
  46. IOpenSSLServerConnectionCreator, IOpenSSLClientConnectionCreator,
  47. IProtocolNegotiationFactory, IHandshakeListener
  48. )
  49. from twisted.internet.main import CONNECTION_LOST
  50. from twisted.internet._producer_helpers import _PullToPush
  51. from twisted.internet.protocol import Protocol
  52. from twisted.internet._sslverify import _setAcceptableProtocols
  53. from twisted.protocols.policies import ProtocolWrapper, WrappingFactory
  54. @implementer(IPushProducer)
  55. class _ProducerMembrane(object):
  56. """
  57. Stand-in for producer registered with a L{TLSMemoryBIOProtocol} transport.
  58. Ensures that producer pause/resume events from the undelying transport are
  59. coordinated with pause/resume events from the TLS layer.
  60. @ivar _producer: The application-layer producer.
  61. """
  62. _producerPaused = False
  63. def __init__(self, producer):
  64. self._producer = producer
  65. def pauseProducing(self):
  66. """
  67. C{pauseProducing} the underlying producer, if it's not paused.
  68. """
  69. if self._producerPaused:
  70. return
  71. self._producerPaused = True
  72. self._producer.pauseProducing()
  73. def resumeProducing(self):
  74. """
  75. C{resumeProducing} the underlying producer, if it's paused.
  76. """
  77. if not self._producerPaused:
  78. return
  79. self._producerPaused = False
  80. self._producer.resumeProducing()
  81. def stopProducing(self):
  82. """
  83. C{stopProducing} the underlying producer.
  84. There is only a single source for this event, so it's simply passed
  85. on.
  86. """
  87. self._producer.stopProducing()
  88. @implementer(ISystemHandle, INegotiated)
  89. class TLSMemoryBIOProtocol(ProtocolWrapper):
  90. """
  91. L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a
  92. memory BIO to encrypt bytes written to it before sending them on to the
  93. underlying transport and decrypts bytes received from the underlying
  94. transport before delivering them to the wrapped protocol.
  95. In addition to producer events from the underlying transport, the need to
  96. wait for reads before a write can proceed means the L{TLSMemoryBIOProtocol}
  97. may also want to pause a producer. Pause/resume events are therefore
  98. merged using the L{_ProducerMembrane} wrapper. Non-streaming (pull)
  99. producers are supported by wrapping them with L{_PullToPush}.
  100. @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is
  101. encrypted and decrypting this connection.
  102. @ivar _lostTLSConnection: A flag indicating whether connection loss has
  103. already been dealt with (C{True}) or not (C{False}). TLS disconnection
  104. is distinct from the underlying connection being lost.
  105. @ivar _appSendBuffer: application-level (cleartext) data that is waiting to
  106. be transferred to the TLS buffer, but can't be because the TLS
  107. connection is handshaking.
  108. @type _appSendBuffer: L{list} of L{bytes}
  109. @ivar _connectWrapped: A flag indicating whether or not to call
  110. C{makeConnection} on the wrapped protocol. This is for the reactor's
  111. L{twisted.internet.interfaces.ITLSTransport.startTLS} implementation,
  112. since it has a protocol which it has already called C{makeConnection}
  113. on, and which has no interest in a new transport. See #3821.
  114. @ivar _handshakeDone: A flag indicating whether or not the handshake is
  115. known to have completed successfully (C{True}) or not (C{False}). This
  116. is used to control error reporting behavior. If the handshake has not
  117. completed, the underlying L{OpenSSL.SSL.Error} will be passed to the
  118. application's C{connectionLost} method. If it has completed, any
  119. unexpected L{OpenSSL.SSL.Error} will be turned into a
  120. L{ConnectionLost}. This is weird; however, it is simply an attempt at
  121. a faithful re-implementation of the behavior provided by
  122. L{twisted.internet.ssl}.
  123. @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes
  124. the connection to be lost, it is saved here. If appropriate, this may
  125. be used as the reason passed to the application protocol's
  126. C{connectionLost} method.
  127. @ivar _producer: The current producer registered via C{registerProducer},
  128. or L{None} if no producer has been registered or a previous one was
  129. unregistered.
  130. @ivar _aborted: C{abortConnection} has been called. No further data will
  131. be received to the wrapped protocol's C{dataReceived}.
  132. @type _aborted: L{bool}
  133. """
  134. _reason = None
  135. _handshakeDone = False
  136. _lostTLSConnection = False
  137. _producer = None
  138. _aborted = False
  139. def __init__(self, factory, wrappedProtocol, _connectWrapped=True):
  140. ProtocolWrapper.__init__(self, factory, wrappedProtocol)
  141. self._connectWrapped = _connectWrapped
  142. def getHandle(self):
  143. """
  144. Return the L{OpenSSL.SSL.Connection} object being used to encrypt and
  145. decrypt this connection.
  146. This is done for the benefit of L{twisted.internet.ssl.Certificate}'s
  147. C{peerFromTransport} and C{hostFromTransport} methods only. A
  148. different system handle may be returned by future versions of this
  149. method.
  150. """
  151. return self._tlsConnection
  152. def makeConnection(self, transport):
  153. """
  154. Connect this wrapper to the given transport and initialize the
  155. necessary L{OpenSSL.SSL.Connection} with a memory BIO.
  156. """
  157. self._tlsConnection = self.factory._createConnection(self)
  158. self._appSendBuffer = []
  159. # Add interfaces provided by the transport we are wrapping:
  160. for interface in providedBy(transport):
  161. directlyProvides(self, interface)
  162. # Intentionally skip ProtocolWrapper.makeConnection - it might call
  163. # wrappedProtocol.makeConnection, which we want to make conditional.
  164. Protocol.makeConnection(self, transport)
  165. self.factory.registerProtocol(self)
  166. if self._connectWrapped:
  167. # Now that the TLS layer is initialized, notify the application of
  168. # the connection.
  169. ProtocolWrapper.makeConnection(self, transport)
  170. # Now that we ourselves have a transport (initialized by the
  171. # ProtocolWrapper.makeConnection call above), kick off the TLS
  172. # handshake.
  173. self._checkHandshakeStatus()
  174. def _checkHandshakeStatus(self):
  175. """
  176. Ask OpenSSL to proceed with a handshake in progress.
  177. Initially, this just sends the ClientHello; after some bytes have been
  178. stuffed in to the C{Connection} object by C{dataReceived}, it will then
  179. respond to any C{Certificate} or C{KeyExchange} messages.
  180. """
  181. # The connection might already be aborted (eg. by a callback during
  182. # connection setup), so don't even bother trying to handshake in that
  183. # case.
  184. if self._aborted:
  185. return
  186. try:
  187. self._tlsConnection.do_handshake()
  188. except WantReadError:
  189. self._flushSendBIO()
  190. except Error:
  191. self._tlsShutdownFinished(Failure())
  192. else:
  193. self._handshakeDone = True
  194. if IHandshakeListener.providedBy(self.wrappedProtocol):
  195. self.wrappedProtocol.handshakeCompleted()
  196. def _flushSendBIO(self):
  197. """
  198. Read any bytes out of the send BIO and write them to the underlying
  199. transport.
  200. """
  201. try:
  202. bytes = self._tlsConnection.bio_read(2 ** 15)
  203. except WantReadError:
  204. # There may be nothing in the send BIO right now.
  205. pass
  206. else:
  207. self.transport.write(bytes)
  208. def _flushReceiveBIO(self):
  209. """
  210. Try to receive any application-level bytes which are now available
  211. because of a previous write into the receive BIO. This will take
  212. care of delivering any application-level bytes which are received to
  213. the protocol, as well as handling of the various exceptions which
  214. can come from trying to get such bytes.
  215. """
  216. # Keep trying this until an error indicates we should stop or we
  217. # close the connection. Looping is necessary to make sure we
  218. # process all of the data which was put into the receive BIO, as
  219. # there is no guarantee that a single recv call will do it all.
  220. while not self._lostTLSConnection:
  221. try:
  222. bytes = self._tlsConnection.recv(2 ** 15)
  223. except WantReadError:
  224. # The newly received bytes might not have been enough to produce
  225. # any application data.
  226. break
  227. except ZeroReturnError:
  228. # TLS has shut down and no more TLS data will be received over
  229. # this connection.
  230. self._shutdownTLS()
  231. # Passing in None means the user protocol's connnectionLost
  232. # will get called with reason from underlying transport:
  233. self._tlsShutdownFinished(None)
  234. except Error:
  235. # Something went pretty wrong. For example, this might be a
  236. # handshake failure during renegotiation (because there were no
  237. # shared ciphers, because a certificate failed to verify, etc).
  238. # TLS can no longer proceed.
  239. failure = Failure()
  240. self._tlsShutdownFinished(failure)
  241. else:
  242. if not self._aborted:
  243. ProtocolWrapper.dataReceived(self, bytes)
  244. # The received bytes might have generated a response which needs to be
  245. # sent now. For example, the handshake involves several round-trip
  246. # exchanges without ever producing application-bytes.
  247. self._flushSendBIO()
  248. def dataReceived(self, bytes):
  249. """
  250. Deliver any received bytes to the receive BIO and then read and deliver
  251. to the application any application-level data which becomes available
  252. as a result of this.
  253. """
  254. # Let OpenSSL know some bytes were just received.
  255. self._tlsConnection.bio_write(bytes)
  256. # If we are still waiting for the handshake to complete, try to
  257. # complete the handshake with the bytes we just received.
  258. if not self._handshakeDone:
  259. self._checkHandshakeStatus()
  260. # If the handshake still isn't finished, then we've nothing left to
  261. # do.
  262. if not self._handshakeDone:
  263. return
  264. # If we've any pending writes, this read may have un-blocked them, so
  265. # attempt to unbuffer them into the OpenSSL layer.
  266. if self._appSendBuffer:
  267. self._unbufferPendingWrites()
  268. # Since the handshake is complete, the wire-level bytes we just
  269. # processed might turn into some application-level bytes; try to pull
  270. # those out.
  271. self._flushReceiveBIO()
  272. def _shutdownTLS(self):
  273. """
  274. Initiate, or reply to, the shutdown handshake of the TLS layer.
  275. """
  276. try:
  277. shutdownSuccess = self._tlsConnection.shutdown()
  278. except Error:
  279. # Mid-handshake, a call to shutdown() can result in a
  280. # WantWantReadError, or rather an SSL_ERR_WANT_READ; but pyOpenSSL
  281. # doesn't allow us to get at the error. See:
  282. # https://github.com/pyca/pyopenssl/issues/91
  283. shutdownSuccess = False
  284. self._flushSendBIO()
  285. if shutdownSuccess:
  286. # Both sides have shutdown, so we can start closing lower-level
  287. # transport. This will also happen if we haven't started
  288. # negotiation at all yet, in which case shutdown succeeds
  289. # immediately.
  290. self.transport.loseConnection()
  291. def _tlsShutdownFinished(self, reason):
  292. """
  293. Called when TLS connection has gone away; tell underlying transport to
  294. disconnect.
  295. @param reason: a L{Failure} whose value is an L{Exception} if we want to
  296. report that failure through to the wrapped protocol's
  297. C{connectionLost}, or L{None} if the C{reason} that
  298. C{connectionLost} should receive should be coming from the
  299. underlying transport.
  300. @type reason: L{Failure} or L{None}
  301. """
  302. if reason is not None:
  303. # Squash an EOF in violation of the TLS protocol into
  304. # ConnectionLost, so that applications which might run over
  305. # multiple protocols can recognize its type.
  306. if tuple(reason.value.args[:2]) == (-1, 'Unexpected EOF'):
  307. reason = Failure(CONNECTION_LOST)
  308. if self._reason is None:
  309. self._reason = reason
  310. self._lostTLSConnection = True
  311. # We may need to send a TLS alert regarding the nature of the shutdown
  312. # here (for example, why a handshake failed), so always flush our send
  313. # buffer before telling our lower-level transport to go away.
  314. self._flushSendBIO()
  315. # Using loseConnection causes the application protocol's
  316. # connectionLost method to be invoked non-reentrantly, which is always
  317. # a nice feature. However, for error cases (reason != None) we might
  318. # want to use abortConnection when it becomes available. The
  319. # loseConnection call is basically tested by test_handshakeFailure.
  320. # At least one side will need to do it or the test never finishes.
  321. self.transport.loseConnection()
  322. def connectionLost(self, reason):
  323. """
  324. Handle the possible repetition of calls to this method (due to either
  325. the underlying transport going away or due to an error at the TLS
  326. layer) and make sure the base implementation only gets invoked once.
  327. """
  328. if not self._lostTLSConnection:
  329. # Tell the TLS connection that it's not going to get any more data
  330. # and give it a chance to finish reading.
  331. self._tlsConnection.bio_shutdown()
  332. self._flushReceiveBIO()
  333. self._lostTLSConnection = True
  334. reason = self._reason or reason
  335. self._reason = None
  336. self.connected = False
  337. ProtocolWrapper.connectionLost(self, reason)
  338. # Breaking reference cycle between self._tlsConnection and self.
  339. self._tlsConnection = None
  340. def loseConnection(self):
  341. """
  342. Send a TLS close alert and close the underlying connection.
  343. """
  344. if self.disconnecting or not self.connected:
  345. return
  346. # If connection setup has not finished, OpenSSL 1.0.2f+ will not shut
  347. # down the connection until we write some data to the connection which
  348. # allows the handshake to complete. However, since no data should be
  349. # written after loseConnection, this means we'll be stuck forever
  350. # waiting for shutdown to complete. Instead, we simply abort the
  351. # connection without trying to shut down cleanly:
  352. if not self._handshakeDone and not self._appSendBuffer:
  353. self.abortConnection()
  354. self.disconnecting = True
  355. if not self._appSendBuffer and self._producer is None:
  356. self._shutdownTLS()
  357. def abortConnection(self):
  358. """
  359. Tear down TLS state so that if the connection is aborted mid-handshake
  360. we don't deliver any further data from the application.
  361. """
  362. self._aborted = True
  363. self.disconnecting = True
  364. self._shutdownTLS()
  365. self.transport.abortConnection()
  366. def failVerification(self, reason):
  367. """
  368. Abort the connection during connection setup, giving a reason that
  369. certificate verification failed.
  370. @param reason: The reason that the verification failed; reported to the
  371. application protocol's C{connectionLost} method.
  372. @type reason: L{Failure}
  373. """
  374. self._reason = reason
  375. self.abortConnection()
  376. def write(self, bytes):
  377. """
  378. Process the given application bytes and send any resulting TLS traffic
  379. which arrives in the send BIO.
  380. If C{loseConnection} was called, subsequent calls to C{write} will
  381. drop the bytes on the floor.
  382. """
  383. if isinstance(bytes, unicode):
  384. raise TypeError("Must write bytes to a TLS transport, not unicode.")
  385. # Writes after loseConnection are not supported, unless a producer has
  386. # been registered, in which case writes can happen until the producer
  387. # is unregistered:
  388. if self.disconnecting and self._producer is None:
  389. return
  390. self._write(bytes)
  391. def _bufferedWrite(self, octets):
  392. """
  393. Put the given octets into L{TLSMemoryBIOProtocol._appSendBuffer}, and
  394. tell any listening producer that it should pause because we are now
  395. buffering.
  396. """
  397. self._appSendBuffer.append(octets)
  398. if self._producer is not None:
  399. self._producer.pauseProducing()
  400. def _unbufferPendingWrites(self):
  401. """
  402. Un-buffer all waiting writes in L{TLSMemoryBIOProtocol._appSendBuffer}.
  403. """
  404. pendingWrites, self._appSendBuffer = self._appSendBuffer, []
  405. for eachWrite in pendingWrites:
  406. self._write(eachWrite)
  407. if self._appSendBuffer:
  408. # If OpenSSL ran out of buffer space in the Connection on our way
  409. # through the loop earlier and re-buffered any of our outgoing
  410. # writes, then we're done; don't consider any future work.
  411. return
  412. if self._producer is not None:
  413. # If we have a registered producer, let it know that we have some
  414. # more buffer space.
  415. self._producer.resumeProducing()
  416. return
  417. if self.disconnecting:
  418. # Finally, if we have no further buffered data, no producer wants
  419. # to send us more data in the future, and the application told us
  420. # to end the stream, initiate a TLS shutdown.
  421. self._shutdownTLS()
  422. def _write(self, bytes):
  423. """
  424. Process the given application bytes and send any resulting TLS traffic
  425. which arrives in the send BIO.
  426. This may be called by C{dataReceived} with bytes that were buffered
  427. before C{loseConnection} was called, which is why this function
  428. doesn't check for disconnection but accepts the bytes regardless.
  429. """
  430. if self._lostTLSConnection:
  431. return
  432. # A TLS payload is 16kB max
  433. bufferSize = 2 ** 14
  434. # How far into the input we've gotten so far
  435. alreadySent = 0
  436. while alreadySent < len(bytes):
  437. toSend = bytes[alreadySent:alreadySent + bufferSize]
  438. try:
  439. sent = self._tlsConnection.send(toSend)
  440. except WantReadError:
  441. self._bufferedWrite(bytes[alreadySent:])
  442. break
  443. except Error:
  444. # Pretend TLS connection disconnected, which will trigger
  445. # disconnect of underlying transport. The error will be passed
  446. # to the application protocol's connectionLost method. The
  447. # other SSL implementation doesn't, but losing helpful
  448. # debugging information is a bad idea.
  449. self._tlsShutdownFinished(Failure())
  450. break
  451. else:
  452. # We've successfully handed off the bytes to the OpenSSL
  453. # Connection object.
  454. alreadySent += sent
  455. # See if OpenSSL wants to hand any bytes off to the underlying
  456. # transport as a result.
  457. self._flushSendBIO()
  458. def writeSequence(self, iovec):
  459. """
  460. Write a sequence of application bytes by joining them into one string
  461. and passing them to L{write}.
  462. """
  463. self.write(b"".join(iovec))
  464. def getPeerCertificate(self):
  465. return self._tlsConnection.get_peer_certificate()
  466. @property
  467. def negotiatedProtocol(self):
  468. """
  469. @see: L{INegotiated.negotiatedProtocol}
  470. """
  471. protocolName = None
  472. try:
  473. # If ALPN is not implemented that's ok, NPN might be.
  474. protocolName = self._tlsConnection.get_alpn_proto_negotiated()
  475. except (NotImplementedError, AttributeError):
  476. pass
  477. if protocolName not in (b'', None):
  478. # A protocol was selected using ALPN.
  479. return protocolName
  480. try:
  481. protocolName = self._tlsConnection.get_next_proto_negotiated()
  482. except (NotImplementedError, AttributeError):
  483. pass
  484. if protocolName != b'':
  485. return protocolName
  486. return None
  487. def registerProducer(self, producer, streaming):
  488. # If we've already disconnected, nothing to do here:
  489. if self._lostTLSConnection:
  490. producer.stopProducing()
  491. return
  492. # If we received a non-streaming producer, wrap it so it becomes a
  493. # streaming producer:
  494. if not streaming:
  495. producer = streamingProducer = _PullToPush(producer, self)
  496. producer = _ProducerMembrane(producer)
  497. # This will raise an exception if a producer is already registered:
  498. self.transport.registerProducer(producer, True)
  499. self._producer = producer
  500. # If we received a non-streaming producer, we need to start the
  501. # streaming wrapper:
  502. if not streaming:
  503. streamingProducer.startStreaming()
  504. def unregisterProducer(self):
  505. # If we have no producer, we don't need to do anything here.
  506. if self._producer is None:
  507. return
  508. # If we received a non-streaming producer, we need to stop the
  509. # streaming wrapper:
  510. if isinstance(self._producer._producer, _PullToPush):
  511. self._producer._producer.stopStreaming()
  512. self._producer = None
  513. self._producerPaused = False
  514. self.transport.unregisterProducer()
  515. if self.disconnecting and not self._appSendBuffer:
  516. self._shutdownTLS()
  517. @implementer(IOpenSSLClientConnectionCreator, IOpenSSLServerConnectionCreator)
  518. class _ContextFactoryToConnectionFactory(object):
  519. """
  520. Adapter wrapping a L{twisted.internet.interfaces.IOpenSSLContextFactory}
  521. into a L{IOpenSSLClientConnectionCreator} or
  522. L{IOpenSSLServerConnectionCreator}.
  523. See U{https://twistedmatrix.com/trac/ticket/7215} for work that should make
  524. this unnecessary.
  525. """
  526. def __init__(self, oldStyleContextFactory):
  527. """
  528. Construct a L{_ContextFactoryToConnectionFactory} with a
  529. L{twisted.internet.interfaces.IOpenSSLContextFactory}.
  530. Immediately call C{getContext} on C{oldStyleContextFactory} in order to
  531. force advance parameter checking, since old-style context factories
  532. don't actually check that their arguments to L{OpenSSL} are correct.
  533. @param oldStyleContextFactory: A factory that can produce contexts.
  534. @type oldStyleContextFactory:
  535. L{twisted.internet.interfaces.IOpenSSLContextFactory}
  536. """
  537. oldStyleContextFactory.getContext()
  538. self._oldStyleContextFactory = oldStyleContextFactory
  539. def _connectionForTLS(self, protocol):
  540. """
  541. Create an L{OpenSSL.SSL.Connection} object.
  542. @param protocol: The protocol initiating a TLS connection.
  543. @type protocol: L{TLSMemoryBIOProtocol}
  544. @return: a connection
  545. @rtype: L{OpenSSL.SSL.Connection}
  546. """
  547. context = self._oldStyleContextFactory.getContext()
  548. return Connection(context, None)
  549. def serverConnectionForTLS(self, protocol):
  550. """
  551. Construct an OpenSSL server connection from the wrapped old-style
  552. context factory.
  553. @note: Since old-style context factories don't distinguish between
  554. clients and servers, this is exactly the same as
  555. L{_ContextFactoryToConnectionFactory.clientConnectionForTLS}.
  556. @param protocol: The protocol initiating a TLS connection.
  557. @type protocol: L{TLSMemoryBIOProtocol}
  558. @return: a connection
  559. @rtype: L{OpenSSL.SSL.Connection}
  560. """
  561. return self._connectionForTLS(protocol)
  562. def clientConnectionForTLS(self, protocol):
  563. """
  564. Construct an OpenSSL server connection from the wrapped old-style
  565. context factory.
  566. @note: Since old-style context factories don't distinguish between
  567. clients and servers, this is exactly the same as
  568. L{_ContextFactoryToConnectionFactory.serverConnectionForTLS}.
  569. @param protocol: The protocol initiating a TLS connection.
  570. @type protocol: L{TLSMemoryBIOProtocol}
  571. @return: a connection
  572. @rtype: L{OpenSSL.SSL.Connection}
  573. """
  574. return self._connectionForTLS(protocol)
  575. class TLSMemoryBIOFactory(WrappingFactory):
  576. """
  577. L{TLSMemoryBIOFactory} adds TLS to connections.
  578. @ivar _creatorInterface: the interface which L{_connectionCreator} is
  579. expected to implement.
  580. @type _creatorInterface: L{zope.interface.interfaces.IInterface}
  581. @ivar _connectionCreator: a callable which creates an OpenSSL Connection
  582. object.
  583. @type _connectionCreator: 1-argument callable taking
  584. L{TLSMemoryBIOProtocol} and returning L{OpenSSL.SSL.Connection}.
  585. """
  586. protocol = TLSMemoryBIOProtocol
  587. noisy = False # disable unnecessary logging.
  588. def __init__(self, contextFactory, isClient, wrappedFactory):
  589. """
  590. Create a L{TLSMemoryBIOFactory}.
  591. @param contextFactory: Configuration parameters used to create an
  592. OpenSSL connection. In order of preference, what you should pass
  593. here should be:
  594. 1. L{twisted.internet.ssl.CertificateOptions} (if you're
  595. writing a server) or the result of
  596. L{twisted.internet.ssl.optionsForClientTLS} (if you're
  597. writing a client). If you want security you should really
  598. use one of these.
  599. 2. If you really want to implement something yourself, supply a
  600. provider of L{IOpenSSLClientConnectionCreator} or
  601. L{IOpenSSLServerConnectionCreator}.
  602. 3. If you really have to, supply a
  603. L{twisted.internet.ssl.ContextFactory}. This will likely be
  604. deprecated at some point so please upgrade to the new
  605. interfaces.
  606. @type contextFactory: L{IOpenSSLClientConnectionCreator} or
  607. L{IOpenSSLServerConnectionCreator}, or, for compatibility with
  608. older code, anything implementing
  609. L{twisted.internet.interfaces.IOpenSSLContextFactory}. See
  610. U{https://twistedmatrix.com/trac/ticket/7215} for information on
  611. the upcoming deprecation of passing a
  612. L{twisted.internet.ssl.ContextFactory} here.
  613. @param isClient: Is this a factory for TLS client connections; in other
  614. words, those that will send a C{ClientHello} greeting? L{True} if
  615. so, L{False} otherwise. This flag determines what interface is
  616. expected of C{contextFactory}. If L{True}, C{contextFactory}
  617. should provide L{IOpenSSLClientConnectionCreator}; otherwise it
  618. should provide L{IOpenSSLServerConnectionCreator}.
  619. @type isClient: L{bool}
  620. @param wrappedFactory: A factory which will create the
  621. application-level protocol.
  622. @type wrappedFactory: L{twisted.internet.interfaces.IProtocolFactory}
  623. """
  624. WrappingFactory.__init__(self, wrappedFactory)
  625. if isClient:
  626. creatorInterface = IOpenSSLClientConnectionCreator
  627. else:
  628. creatorInterface = IOpenSSLServerConnectionCreator
  629. self._creatorInterface = creatorInterface
  630. if not creatorInterface.providedBy(contextFactory):
  631. contextFactory = _ContextFactoryToConnectionFactory(contextFactory)
  632. self._connectionCreator = contextFactory
  633. def logPrefix(self):
  634. """
  635. Annotate the wrapped factory's log prefix with some text indicating TLS
  636. is in use.
  637. @rtype: C{str}
  638. """
  639. if ILoggingContext.providedBy(self.wrappedFactory):
  640. logPrefix = self.wrappedFactory.logPrefix()
  641. else:
  642. logPrefix = self.wrappedFactory.__class__.__name__
  643. return "%s (TLS)" % (logPrefix,)
  644. def _applyProtocolNegotiation(self, connection):
  645. """
  646. Applies ALPN/NPN protocol neogitation to the connection, if the factory
  647. supports it.
  648. @param connection: The OpenSSL connection object to have ALPN/NPN added
  649. to it.
  650. @type connection: L{OpenSSL.SSL.Connection}
  651. @return: Nothing
  652. @rtype: L{None}
  653. """
  654. if IProtocolNegotiationFactory.providedBy(self.wrappedFactory):
  655. protocols = self.wrappedFactory.acceptableProtocols()
  656. context = connection.get_context()
  657. _setAcceptableProtocols(context, protocols)
  658. return
  659. def _createConnection(self, tlsProtocol):
  660. """
  661. Create an OpenSSL connection and set it up good.
  662. @param tlsProtocol: The protocol which is establishing the connection.
  663. @type tlsProtocol: L{TLSMemoryBIOProtocol}
  664. @return: an OpenSSL connection object for C{tlsProtocol} to use
  665. @rtype: L{OpenSSL.SSL.Connection}
  666. """
  667. connectionCreator = self._connectionCreator
  668. if self._creatorInterface is IOpenSSLClientConnectionCreator:
  669. connection = connectionCreator.clientConnectionForTLS(tlsProtocol)
  670. self._applyProtocolNegotiation(connection)
  671. connection.set_connect_state()
  672. else:
  673. connection = connectionCreator.serverConnectionForTLS(tlsProtocol)
  674. self._applyProtocolNegotiation(connection)
  675. connection.set_accept_state()
  676. return connection