aboutsummaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/protocols/tls.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/protocols/tls.py')
-rwxr-xr-xlib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/protocols/tls.py613
1 files changed, 0 insertions, 613 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/protocols/tls.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/protocols/tls.py
deleted file mode 100755
index a1b782f8..00000000
--- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/protocols/tls.py
+++ /dev/null
@@ -1,613 +0,0 @@
-# -*- test-case-name: twisted.protocols.test.test_tls,twisted.internet.test.test_tls,twisted.test.test_sslverify -*-
-# Copyright (c) Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-"""
-Implementation of a TLS transport (L{ISSLTransport}) as an
-L{IProtocol<twisted.internet.interfaces.IProtocol>} layered on top of any
-L{ITransport<twisted.internet.interfaces.ITransport>} implementation, based on
-U{OpenSSL<http://www.openssl.org>}'s memory BIO features.
-
-L{TLSMemoryBIOFactory} is a L{WrappingFactory} which wraps protocols created by
-the factory it wraps with L{TLSMemoryBIOProtocol}. L{TLSMemoryBIOProtocol}
-intercedes between the underlying transport and the wrapped protocol to
-implement SSL and TLS. Typical usage of this module looks like this::
-
- from twisted.protocols.tls import TLSMemoryBIOFactory
- from twisted.internet.protocol import ServerFactory
- from twisted.internet.ssl import PrivateCertificate
- from twisted.internet import reactor
-
- from someapplication import ApplicationProtocol
-
- serverFactory = ServerFactory()
- serverFactory.protocol = ApplicationProtocol
- certificate = PrivateCertificate.loadPEM(certPEMData)
- contextFactory = certificate.options()
- tlsFactory = TLSMemoryBIOFactory(contextFactory, False, serverFactory)
- reactor.listenTCP(12345, tlsFactory)
- reactor.run()
-
-This API offers somewhat more flexibility than
-L{twisted.internet.interfaces.IReactorSSL}; for example, a L{TLSMemoryBIOProtocol}
-instance can use another instance of L{TLSMemoryBIOProtocol} as its transport,
-yielding TLS over TLS - useful to implement onion routing. It can also be used
-to run TLS over unusual transports, such as UNIX sockets and stdio.
-"""
-
-
-from OpenSSL.SSL import Error, ZeroReturnError, WantReadError
-from OpenSSL.SSL import TLSv1_METHOD, Context, Connection
-
-try:
- Connection(Context(TLSv1_METHOD), None)
-except TypeError, e:
- if str(e) != "argument must be an int, or have a fileno() method.":
- raise
- raise ImportError("twisted.protocols.tls requires pyOpenSSL 0.10 or newer.")
-
-from zope.interface import implements, providedBy, directlyProvides
-
-from twisted.python.failure import Failure
-from twisted.python import log
-from twisted.python.reflect import safe_str
-from twisted.internet.interfaces import ISystemHandle, ISSLTransport
-from twisted.internet.interfaces import IPushProducer, ILoggingContext
-from twisted.internet.main import CONNECTION_LOST
-from twisted.internet.protocol import Protocol
-from twisted.internet.task import cooperate
-from twisted.protocols.policies import ProtocolWrapper, WrappingFactory
-
-
-class _PullToPush(object):
- """
- An adapter that converts a non-streaming to a streaming producer.
-
- Because of limitations of the producer API, this adapter requires the
- cooperation of the consumer. When the consumer's C{registerProducer} is
- called with a non-streaming producer, it must wrap it with L{_PullToPush}
- and then call C{startStreaming} on the resulting object. When the
- consumer's C{unregisterProducer} is called, it must call
- C{stopStreaming} on the L{_PullToPush} instance.
-
- If the underlying producer throws an exception from C{resumeProducing},
- the producer will be unregistered from the consumer.
-
- @ivar _producer: the underling non-streaming producer.
-
- @ivar _consumer: the consumer with which the underlying producer was
- registered.
-
- @ivar _finished: C{bool} indicating whether the producer has finished.
-
- @ivar _coopTask: the result of calling L{cooperate}, the task driving the
- streaming producer.
- """
- implements(IPushProducer)
-
- _finished = False
-
-
- def __init__(self, pullProducer, consumer):
- self._producer = pullProducer
- self._consumer = consumer
-
-
- def _pull(self):
- """
- A generator that calls C{resumeProducing} on the underlying producer
- forever.
-
- If C{resumeProducing} throws an exception, the producer is
- unregistered, which should result in streaming stopping.
- """
- while True:
- try:
- self._producer.resumeProducing()
- except:
- log.err(None, "%s failed, producing will be stopped:" %
- (safe_str(self._producer),))
- try:
- self._consumer.unregisterProducer()
- # The consumer should now call stopStreaming() on us,
- # thus stopping the streaming.
- except:
- # Since the consumer blew up, we may not have had
- # stopStreaming() called, so we just stop on our own:
- log.err(None, "%s failed to unregister producer:" %
- (safe_str(self._consumer),))
- self._finished = True
- return
- yield None
-
-
- def startStreaming(self):
- """
- This should be called by the consumer when the producer is registered.
-
- Start streaming data to the consumer.
- """
- self._coopTask = cooperate(self._pull())
-
-
- def stopStreaming(self):
- """
- This should be called by the consumer when the producer is unregistered.
-
- Stop streaming data to the consumer.
- """
- if self._finished:
- return
- self._finished = True
- self._coopTask.stop()
-
-
- # IPushProducer implementation:
- def pauseProducing(self):
- self._coopTask.pause()
-
-
- def resumeProducing(self):
- self._coopTask.resume()
-
-
- def stopProducing(self):
- self.stopStreaming()
- self._producer.stopProducing()
-
-
-
-class _ProducerMembrane(object):
- """
- Stand-in for producer registered with a L{TLSMemoryBIOProtocol} transport.
-
- Ensures that producer pause/resume events from the undelying transport are
- coordinated with pause/resume events from the TLS layer.
-
- @ivar _producer: The application-layer producer.
- """
- implements(IPushProducer)
-
- _producerPaused = False
-
- def __init__(self, producer):
- self._producer = producer
-
-
- def pauseProducing(self):
- """
- C{pauseProducing} the underlying producer, if it's not paused.
- """
- if self._producerPaused:
- return
- self._producerPaused = True
- self._producer.pauseProducing()
-
-
- def resumeProducing(self):
- """
- C{resumeProducing} the underlying producer, if it's paused.
- """
- if not self._producerPaused:
- return
- self._producerPaused = False
- self._producer.resumeProducing()
-
-
- def stopProducing(self):
- """
- C{stopProducing} the underlying producer.
-
- There is only a single source for this event, so it's simply passed
- on.
- """
- self._producer.stopProducing()
-
-
-
-class TLSMemoryBIOProtocol(ProtocolWrapper):
- """
- L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a
- memory BIO to encrypt bytes written to it before sending them on to the
- underlying transport and decrypts bytes received from the underlying
- transport before delivering them to the wrapped protocol.
-
- In addition to producer events from the underlying transport, the need to
- wait for reads before a write can proceed means the
- L{TLSMemoryBIOProtocol} may also want to pause a producer. Pause/resume
- events are therefore merged using the L{_ProducerMembrane}
- wrapper. Non-streaming (pull) producers are supported by wrapping them
- with L{_PullToPush}.
-
- @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is
- encrypted and decrypting this connection.
-
- @ivar _lostTLSConnection: A flag indicating whether connection loss has
- already been dealt with (C{True}) or not (C{False}). TLS disconnection
- is distinct from the underlying connection being lost.
-
- @ivar _writeBlockedOnRead: A flag indicating whether further writing must
- wait for data to be received (C{True}) or not (C{False}).
-
- @ivar _appSendBuffer: A C{list} of C{str} of application-level (cleartext)
- data which is waiting for C{_writeBlockedOnRead} to be reset to
- C{False} so it can be passed to and perhaps accepted by
- C{_tlsConnection.send}.
-
- @ivar _connectWrapped: A flag indicating whether or not to call
- C{makeConnection} on the wrapped protocol. This is for the reactor's
- L{twisted.internet.interfaces.ITLSTransport.startTLS} implementation,
- since it has a protocol which it has already called C{makeConnection}
- on, and which has no interest in a new transport. See #3821.
-
- @ivar _handshakeDone: A flag indicating whether or not the handshake is
- known to have completed successfully (C{True}) or not (C{False}). This
- is used to control error reporting behavior. If the handshake has not
- completed, the underlying L{OpenSSL.SSL.Error} will be passed to the
- application's C{connectionLost} method. If it has completed, any
- unexpected L{OpenSSL.SSL.Error} will be turned into a
- L{ConnectionLost}. This is weird; however, it is simply an attempt at
- a faithful re-implementation of the behavior provided by
- L{twisted.internet.ssl}.
-
- @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes
- the connection to be lost, it is saved here. If appropriate, this may
- be used as the reason passed to the application protocol's
- C{connectionLost} method.
-
- @ivar _producer: The current producer registered via C{registerProducer},
- or C{None} if no producer has been registered or a previous one was
- unregistered.
- """
- implements(ISystemHandle, ISSLTransport)
-
- _reason = None
- _handshakeDone = False
- _lostTLSConnection = False
- _writeBlockedOnRead = False
- _producer = None
-
- def __init__(self, factory, wrappedProtocol, _connectWrapped=True):
- ProtocolWrapper.__init__(self, factory, wrappedProtocol)
- self._connectWrapped = _connectWrapped
-
-
- def getHandle(self):
- """
- Return the L{OpenSSL.SSL.Connection} object being used to encrypt and
- decrypt this connection.
-
- This is done for the benefit of L{twisted.internet.ssl.Certificate}'s
- C{peerFromTransport} and C{hostFromTransport} methods only. A
- different system handle may be returned by future versions of this
- method.
- """
- return self._tlsConnection
-
-
- def makeConnection(self, transport):
- """
- Connect this wrapper to the given transport and initialize the
- necessary L{OpenSSL.SSL.Connection} with a memory BIO.
- """
- tlsContext = self.factory._contextFactory.getContext()
- self._tlsConnection = Connection(tlsContext, None)
- if self.factory._isClient:
- self._tlsConnection.set_connect_state()
- else:
- self._tlsConnection.set_accept_state()
- self._appSendBuffer = []
-
- # Add interfaces provided by the transport we are wrapping:
- for interface in providedBy(transport):
- directlyProvides(self, interface)
-
- # Intentionally skip ProtocolWrapper.makeConnection - it might call
- # wrappedProtocol.makeConnection, which we want to make conditional.
- Protocol.makeConnection(self, transport)
- self.factory.registerProtocol(self)
- if self._connectWrapped:
- # Now that the TLS layer is initialized, notify the application of
- # the connection.
- ProtocolWrapper.makeConnection(self, transport)
-
- # Now that we ourselves have a transport (initialized by the
- # ProtocolWrapper.makeConnection call above), kick off the TLS
- # handshake.
- try:
- self._tlsConnection.do_handshake()
- except WantReadError:
- # This is the expected case - there's no data in the connection's
- # input buffer yet, so it won't be able to complete the whole
- # handshake now. If this is the speak-first side of the
- # connection, then some bytes will be in the send buffer now; flush
- # them.
- self._flushSendBIO()
-
-
- def _flushSendBIO(self):
- """
- Read any bytes out of the send BIO and write them to the underlying
- transport.
- """
- try:
- bytes = self._tlsConnection.bio_read(2 ** 15)
- except WantReadError:
- # There may be nothing in the send BIO right now.
- pass
- else:
- self.transport.write(bytes)
-
-
- def _flushReceiveBIO(self):
- """
- Try to receive any application-level bytes which are now available
- because of a previous write into the receive BIO. This will take
- care of delivering any application-level bytes which are received to
- the protocol, as well as handling of the various exceptions which
- can come from trying to get such bytes.
- """
- # Keep trying this until an error indicates we should stop or we
- # close the connection. Looping is necessary to make sure we
- # process all of the data which was put into the receive BIO, as
- # there is no guarantee that a single recv call will do it all.
- while not self._lostTLSConnection:
- try:
- bytes = self._tlsConnection.recv(2 ** 15)
- except WantReadError:
- # The newly received bytes might not have been enough to produce
- # any application data.
- break
- except ZeroReturnError:
- # TLS has shut down and no more TLS data will be received over
- # this connection.
- self._shutdownTLS()
- # Passing in None means the user protocol's connnectionLost
- # will get called with reason from underlying transport:
- self._tlsShutdownFinished(None)
- except Error, e:
- # Something went pretty wrong. For example, this might be a
- # handshake failure (because there were no shared ciphers, because
- # a certificate failed to verify, etc). TLS can no longer proceed.
-
- # Squash EOF in violation of protocol into ConnectionLost; we
- # create Failure before calling _flushSendBio so that no new
- # exception will get thrown in the interim.
- if e.args[0] == -1 and e.args[1] == 'Unexpected EOF':
- failure = Failure(CONNECTION_LOST)
- else:
- failure = Failure()
-
- self._flushSendBIO()
- self._tlsShutdownFinished(failure)
- else:
- # If we got application bytes, the handshake must be done by
- # now. Keep track of this to control error reporting later.
- self._handshakeDone = True
- ProtocolWrapper.dataReceived(self, bytes)
-
- # The received bytes might have generated a response which needs to be
- # sent now. For example, the handshake involves several round-trip
- # exchanges without ever producing application-bytes.
- self._flushSendBIO()
-
-
- def dataReceived(self, bytes):
- """
- Deliver any received bytes to the receive BIO and then read and deliver
- to the application any application-level data which becomes available
- as a result of this.
- """
- self._tlsConnection.bio_write(bytes)
-
- if self._writeBlockedOnRead:
- # A read just happened, so we might not be blocked anymore. Try to
- # flush all the pending application bytes.
- self._writeBlockedOnRead = False
- appSendBuffer = self._appSendBuffer
- self._appSendBuffer = []
- for bytes in appSendBuffer:
- self._write(bytes)
- if (not self._writeBlockedOnRead and self.disconnecting and
- self.producer is None):
- self._shutdownTLS()
- if self._producer is not None:
- self._producer.resumeProducing()
-
- self._flushReceiveBIO()
-
-
- def _shutdownTLS(self):
- """
- Initiate, or reply to, the shutdown handshake of the TLS layer.
- """
- shutdownSuccess = self._tlsConnection.shutdown()
- self._flushSendBIO()
- if shutdownSuccess:
- # Both sides have shutdown, so we can start closing lower-level
- # transport. This will also happen if we haven't started
- # negotiation at all yet, in which case shutdown succeeds
- # immediately.
- self.transport.loseConnection()
-
-
- def _tlsShutdownFinished(self, reason):
- """
- Called when TLS connection has gone away; tell underlying transport to
- disconnect.
- """
- self._reason = reason
- self._lostTLSConnection = True
- # Using loseConnection causes the application protocol's
- # connectionLost method to be invoked non-reentrantly, which is always
- # a nice feature. However, for error cases (reason != None) we might
- # want to use abortConnection when it becomes available. The
- # loseConnection call is basically tested by test_handshakeFailure.
- # At least one side will need to do it or the test never finishes.
- self.transport.loseConnection()
-
-
- def connectionLost(self, reason):
- """
- Handle the possible repetition of calls to this method (due to either
- the underlying transport going away or due to an error at the TLS
- layer) and make sure the base implementation only gets invoked once.
- """
- if not self._lostTLSConnection:
- # Tell the TLS connection that it's not going to get any more data
- # and give it a chance to finish reading.
- self._tlsConnection.bio_shutdown()
- self._flushReceiveBIO()
- self._lostTLSConnection = True
- reason = self._reason or reason
- self._reason = None
- ProtocolWrapper.connectionLost(self, reason)
-
-
- def loseConnection(self):
- """
- Send a TLS close alert and close the underlying connection.
- """
- if self.disconnecting:
- return
- self.disconnecting = True
- if not self._writeBlockedOnRead and self._producer is None:
- self._shutdownTLS()
-
-
- def write(self, bytes):
- """
- Process the given application bytes and send any resulting TLS traffic
- which arrives in the send BIO.
-
- If C{loseConnection} was called, subsequent calls to C{write} will
- drop the bytes on the floor.
- """
- # Writes after loseConnection are not supported, unless a producer has
- # been registered, in which case writes can happen until the producer
- # is unregistered:
- if self.disconnecting and self._producer is None:
- return
- self._write(bytes)
-
-
- def _write(self, bytes):
- """
- Process the given application bytes and send any resulting TLS traffic
- which arrives in the send BIO.
-
- This may be called by C{dataReceived} with bytes that were buffered
- before C{loseConnection} was called, which is why this function
- doesn't check for disconnection but accepts the bytes regardless.
- """
- if self._lostTLSConnection:
- return
-
- leftToSend = bytes
- while leftToSend:
- try:
- sent = self._tlsConnection.send(leftToSend)
- except WantReadError:
- self._writeBlockedOnRead = True
- self._appSendBuffer.append(leftToSend)
- if self._producer is not None:
- self._producer.pauseProducing()
- break
- except Error:
- # Pretend TLS connection disconnected, which will trigger
- # disconnect of underlying transport. The error will be passed
- # to the application protocol's connectionLost method. The
- # other SSL implementation doesn't, but losing helpful
- # debugging information is a bad idea.
- self._tlsShutdownFinished(Failure())
- break
- else:
- # If we sent some bytes, the handshake must be done. Keep
- # track of this to control error reporting behavior.
- self._handshakeDone = True
- self._flushSendBIO()
- leftToSend = leftToSend[sent:]
-
-
- def writeSequence(self, iovec):
- """
- Write a sequence of application bytes by joining them into one string
- and passing them to L{write}.
- """
- self.write("".join(iovec))
-
-
- def getPeerCertificate(self):
- return self._tlsConnection.get_peer_certificate()
-
-
- def registerProducer(self, producer, streaming):
- # If we've already disconnected, nothing to do here:
- if self._lostTLSConnection:
- producer.stopProducing()
- return
-
- # If we received a non-streaming producer, wrap it so it becomes a
- # streaming producer:
- if not streaming:
- producer = streamingProducer = _PullToPush(producer, self)
- producer = _ProducerMembrane(producer)
- # This will raise an exception if a producer is already registered:
- self.transport.registerProducer(producer, True)
- self._producer = producer
- # If we received a non-streaming producer, we need to start the
- # streaming wrapper:
- if not streaming:
- streamingProducer.startStreaming()
-
-
- def unregisterProducer(self):
- # If we received a non-streaming producer, we need to stop the
- # streaming wrapper:
- if isinstance(self._producer._producer, _PullToPush):
- self._producer._producer.stopStreaming()
- self._producer = None
- self._producerPaused = False
- self.transport.unregisterProducer()
- if self.disconnecting and not self._writeBlockedOnRead:
- self._shutdownTLS()
-
-
-
-class TLSMemoryBIOFactory(WrappingFactory):
- """
- L{TLSMemoryBIOFactory} adds TLS to connections.
-
- @ivar _contextFactory: The TLS context factory which will be used to define
- certain TLS connection parameters.
-
- @ivar _isClient: A flag which is C{True} if this is a client TLS
- connection, C{False} if it is a server TLS connection.
- """
- protocol = TLSMemoryBIOProtocol
-
- noisy = False # disable unnecessary logging.
-
- def __init__(self, contextFactory, isClient, wrappedFactory):
- WrappingFactory.__init__(self, wrappedFactory)
- self._contextFactory = contextFactory
- self._isClient = isClient
-
- # Force some parameter checking in pyOpenSSL. It's better to fail now
- # than after we've set up the transport.
- contextFactory.getContext()
-
-
- def logPrefix(self):
- """
- Annotate the wrapped factory's log prefix with some text indicating TLS
- is in use.
-
- @rtype: C{str}
- """
- if ILoggingContext.providedBy(self.wrappedFactory):
- logPrefix = self.wrappedFactory.logPrefix()
- else:
- logPrefix = self.wrappedFactory.__class__.__name__
- return "%s (TLS)" % (logPrefix,)
-