Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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