def action_rewrite_ssl(self, host, ip, port, resturi, headers, data, clientproto): class FakeFactory: def log(self, meh): pass FakeFactory.host = host FakeFactory.port = port FakeFactory.root = self.channel.factory.root rp = ReverseProxy() rp.factory = FakeFactory() contextFactory = ssl.DefaultOpenSSLContextFactory(sibpath('server.key'), sibpath('server.crt')) class FakeFactory2: _contextFactory = contextFactory _isClient = False def registerProtocol(self, meh): pass def unregisterProtocol(self, meh): pass ssl_rp = TLSMemoryBIOProtocol(FakeFactory2(), rp) self.channel._registerTunnel(ssl_rp) ssl_rp.makeConnection(self.transport) self.setResponseCode(200) self.write("")
def test_loseConnectionTwice(self): """ If TLSMemoryBIOProtocol.loseConnection is called multiple times, all but the first call have no effect. """ wrapperFactory = TLSMemoryBIOFactory(ClientContextFactory(), True, ClientFactory()) tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, Protocol()) transport = StringTransport() tlsProtocol.makeConnection(transport) self.assertEqual(tlsProtocol.disconnecting, False) # Make sure loseConnection calls _shutdownTLS the first time (mostly # to make sure we've overriding it correctly): calls = [] def _shutdownTLS(shutdown=tlsProtocol._shutdownTLS): calls.append(1) return shutdown() tlsProtocol._shutdownTLS = _shutdownTLS tlsProtocol.loseConnection() self.assertEqual(tlsProtocol.disconnecting, True) self.assertEqual(calls, [1]) # Make sure _shutdownTLS isn't called a second time: tlsProtocol.loseConnection() self.assertEqual(calls, [1])
def test_connectionLostOnlyAfterUnderlyingCloses(self): """ The user protocol's connectionLost is only called when transport underlying TLS is disconnected. """ class LostProtocol(Protocol): disconnected = None def connectionLost(self, reason): self.disconnected = reason wrapperFactory = TLSMemoryBIOFactory(ClientContextFactory(), True, ClientFactory()) protocol = LostProtocol() tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, protocol) transport = StringTransport() tlsProtocol.makeConnection(transport) # Pretend TLS shutdown finished cleanly; the underlying transport # should be told to close, but the user protocol should not yet be # notified: tlsProtocol._tlsShutdownFinished(None) self.assertEqual(transport.disconnecting, True) self.assertEqual(protocol.disconnected, None) # Now close the underlying connection; the user protocol should be # notified with the given reason (since TLS closed cleanly): tlsProtocol.connectionLost(Failure(ConnectionLost("ono"))) self.assertTrue(protocol.disconnected.check(ConnectionLost)) self.assertEqual(protocol.disconnected.value.args, ("ono",))
def startTLS(self, contextFactory, client, bytes=None): """ Add a layer of TLS, with SSL parameters defined by the given contextFactory. If *client* is True, this side of the connection will be an SSL client. Otherwise it will be an SSL server. If extra bytes which may be (or almost certainly are) part of the SSL handshake were received by the protocol running on top of OnionProtocol, they must be passed here as the **bytes** parameter. """ # The newest TLS session is spliced in between the previous # and the application protocol at the tail end of the list. tlsProtocol = TLSMemoryBIOProtocol(None, self._tailProtocol, False) tlsProtocol.factory = TLSMemoryBIOFactory(contextFactory, client, None) if self._currentProtocol is self._tailProtocol: # This is the first and thus outermost TLS session. The # transport is the immutable sentinel that no startTLS or # stopTLS call will move within the linked list stack. # The wrappedProtocol will remain this outermost session # until it's terminated. self.wrappedProtocol = tlsProtocol nextTransport = PopOnDisconnectTransport(original=self.transport, pop=self._pop) # Store the proxied transport as the list's head sentinel # to enable an easy identity check in _pop. self._headTransport = nextTransport else: # This a later TLS session within the stack. The previous # TLS session becomes its transport. nextTransport = PopOnDisconnectTransport( original=self._currentProtocol, pop=self._pop) # Splice the new TLS session into the linked list stack. # wrappedProtocol serves as the link, so the protocol at the # current position takes our new TLS session as its # wrappedProtocol. self._currentProtocol.wrappedProtocol = tlsProtocol # Move down one position in the linked list. self._currentProtocol = tlsProtocol # Expose the new, innermost TLS session as the transport to # the application protocol. self.transport = self._currentProtocol # Connect the new TLS session to the previous transport. The # transport attribute also serves as the previous link. tlsProtocol.makeConnection(nextTransport) # Left over bytes are part of the latest handshake. Pass them # on to the innermost TLS session. if bytes is not None: tlsProtocol.dataReceived(bytes)
def test_getHandle(self): """ L{TLSMemoryBIOProtocol.getHandle} returns the L{OpenSSL.SSL.Connection} instance it uses to actually implement TLS. This may seem odd. In fact, it is. The L{OpenSSL.SSL.Connection} is not actually the "system handle" here, nor even an object the reactor knows about directly. However, L{twisted.internet.ssl.Certificate}'s C{peerFromTransport} and C{hostFromTransport} methods depend on being able to get an L{OpenSSL.SSL.Connection} object in order to work properly. Implementing L{ISystemHandle.getHandle} like this is the easiest way for those APIs to be made to work. If they are changed, then it may make sense to get rid of this implementation of L{ISystemHandle} and return the underlying socket instead. """ factory = ClientFactory() contextFactory = ClientContextFactory() wrapperFactory = TLSMemoryBIOFactory(contextFactory, True, factory) proto = TLSMemoryBIOProtocol(wrapperFactory, Protocol()) transport = StringTransport() proto.makeConnection(transport) self.assertIsInstance(proto.getHandle(), ConnectionType)