Santiago.verify_sender works; commented out old test stubs.

This commit is contained in:
Nick Daly 2012-05-10 07:23:47 -05:00
parent 3ffbe02cb6
commit 5cc01cc92d
2 changed files with 491 additions and 391 deletions

View File

@ -364,16 +364,18 @@ class Santiago(object):
allowed to send us messages. allowed to send us messages.
""" """
if not request.gpg.valid: gpg_data = request.next()
if not gpg_data:
raise InvalidSignatureError() raise InvalidSignatureError()
if not self.get_host_locations(request.gpg.fingerprint, "santiago"): if not self.get_host_locations(gpg_data.fingerprint, "santiago"):
raise UnwillingHostError( raise UnwillingHostError(
"{0} is not a Santiago client.".format(request.gpg.fingerprint)) "{0} is not a Santiago client.".format(gpg_data.fingerprint))
return request_body return request
def verify_client(self, request_body, proxied_request): def verify_client(self, request):
"""Verify the signature of the message's source. """Verify the signature of the message's source.
This is part (B) in the message diagram. This is part (B) in the message diagram.
@ -387,16 +389,19 @@ class Santiago(object):
somebody else. somebody else.
""" """
self.verify_client(request_body) self.verify_sender(request)
if not request_body: adict = None
try:
adict = dict(request.message)
except:
return return
if not self.i_am(request_body["to"]): if not self.i_am(adict["to"]):
self.proxy(proxied_request) self.proxy(adict["request"])
return return
return request_body return request
def decrypt_client(self, request_body): def decrypt_client(self, request_body):
"""Decrypt the message and validates the encrypted signature. """Decrypt the message and validates the encrypted signature.

View File

@ -40,418 +40,512 @@ If I produce a listener that just echoes the parameters, I can validate the resp
""" """
import unittest import ConfigParser as configparser
import os import os
import sys import sys
import unittest
from pprint import pprint from pprint import pprint
import gnupg import gnupg
import simplesantiago import logging
from errors import InvalidSignatureError, UnwillingHostError
import simplesantiago as santiago
class SantiagoTest(unittest.TestCase): import test_pgpprocessor
"""The base class for tests.""" import pgpprocessor
def setUp(self):
super(TestServing, self).setUp() # class SantiagoTest(unittest.TestCase):
# """The base class for tests."""
port_a = "localhost:9000" #
port_b = "localhost:8000" # def setUp(self):
# super(TestServing, self).setUp()
listeners_a = [santiago.SantiagoListener(port_a)] #
senders_a = [santiago.SantiagoSender()] # port_a = "localhost:9000"
listeners_b = [santiago.SantiagoListener(port_b)] # port_b = "localhost:8000"
senders_b = [santiago.SantiagoSender()] #
# listeners_a = [santiago.SantiagoListener(port_a)]
hosting_a = { "b": { "santiago": [ port_a ]}} # senders_a = [santiago.SantiagoSender()]
consuming_a = { "santiagao": { "b": [ port_b ]}} # listeners_b = [santiago.SantiagoListener(port_b)]
# senders_b = [santiago.SantiagoSender()]
hosting_b = { "a": { "santiago": [ port_b ], #
"wiki": [ "localhost:8001" ]}} # hosting_a = { "b": { "santiago": [ port_a ]}}
consuming_b = { "santiagao": { "a": [ port_a ]}} # consuming_a = { "santiagao": { "b": [ port_b ]}}
#
self.santiago_a = Santiago(listeners_a, senders_a, hosting_a, consuming_a) # hosting_b = { "a": { "santiago": [ port_b ],
self.santiago_b = Santiago(listeners_b, senders_b, hosting_b, consuming_b) # "wiki": [ "localhost:8001" ]}}
# consuming_b = { "santiagao": { "a": [ port_a ]}}
def serveOnPort(self, port): #
"""Start listening for connections on a named port. # self.santiago_a = Santiago(listeners_a, senders_a, hosting_a, consuming_a)
# self.santiago_b = Santiago(listeners_b, senders_b, hosting_b, consuming_b)
Used in testing as a mock listener for responses from a Santiago server. #
# def serveOnPort(self, port):
""" # """Start listening for connections on a named port.
class RequestReceiver(object): #
"""A very basic listener. # Used in testing as a mock listener for responses from a Santiago server.
#
It merely records the calling arguments. # """
# class RequestReceiver(object):
""" # """A very basic listener.
@cherrypy.expose #
def index(self, *args, **kwargs): # It merely records the calling arguments.
self.args = args #
self.kwargs = kwargs # """
# @cherrypy.expose
self.socket_port = port # def index(self, *args, **kwargs):
# self.args = args
self.receiver = RequestReceiver() # self.kwargs = kwargs
#
cherrypy.quickstart(self.receiver) # self.socket_port = port
#
if sys.version_info < (2, 7): # self.receiver = RequestReceiver()
"""Add a poor man's forward compatibility.""" #
# cherrypy.quickstart(self.receiver)
class ContainsError(AssertionError): #
pass # if sys.version_info < (2, 7):
# """Add a poor man's forward compatibility."""
def assertIn(self, a, b): #
if not a in b: # class ContainsError(AssertionError):
raise self.ContainsError("%s not in %s" % (a, b)) # pass
#
class TestClientInitialRequest(SantiagoTest): # def assertIn(self, a, b):
"""Does the client send a correctly formed request? # if not a in b:
# raise self.ContainsError("%s not in %s" % (a, b))
In these tests, we're sending requests to a mock listener which merely #
records that the requests were well-formed. # class TestClientInitialRequest(SantiagoTest):
# """Does the client send a correctly formed request?
""" #
def setUp(self): # In these tests, we're sending requests to a mock listener which merely
super(SantiagoTest, self).setUp() # records that the requests were well-formed.
#
self.serveOnPort(8000) # """
# def setUp(self):
def test_request(self): # super(SantiagoTest, self).setUp()
"""Verify that A queues a properly formatted initial request.""" #
# self.serveOnPort(8000)
self.santiago_a.request(from_="a", to="b", #
client="a", host="b", # def test_request(self):
service="wiki", reply_to="localhost:9001") # """Verify that A queues a properly formatted initial request."""
#
self.assertEqual(self.santiago_a.outgoing_messages, # self.santiago_a.request(from_="a", to="b",
[{ "from": "a", "to": "b", # client="a", host="b",
"client": "a", "host": "b", # service="wiki", reply_to="localhost:9001")
"service": "wiki", "reply-to": "localhost:9001"}]) #
# self.assertEqual(self.santiago_a.outgoing_messages,
def test_request(self): # [{ "from": "a", "to": "b",
"""Verify that A sends out a properly formatted initial request.""" # "client": "a", "host": "b",
# "service": "wiki", "reply-to": "localhost:9001"}])
self.santiago_a.request(from_="a", to="b", #
client="a", host="b", # def test_request(self):
service="wiki", reply_to="localhost:9001") # """Verify that A sends out a properly formatted initial request."""
#
self.santiago_a.process() # self.santiago_a.request(from_="a", to="b",
# client="a", host="b",
self.assertEqual(self.receiver.kwargs, # service="wiki", reply_to="localhost:9001")
[{ "from": "a", "to": "b", #
"client": "a", "host": "b", # self.santiago_a.process()
"service": "wiki", "reply-to": "localhost:9001"}]) #
# self.assertEqual(self.receiver.kwargs,
class TestServerInitialRequest(SantiagoTest): # [{ "from": "a", "to": "b",
"""Test how the Santiago server replies to initial service requests. # "client": "a", "host": "b",
# "service": "wiki", "reply-to": "localhost:9001"}])
TODO: Add a mock listener to represent A. #
TODO: Transform the data structure tests into the mock-response tests. # class TestServerInitialRequest(SantiagoTest):
TODO tests: (normal serving + proxying) * (learning santiagi + not learning) # """Test how the Santiago server replies to initial service requests.
#
Proxying # TODO: Add a mock listener to represent A.
~~~~~~~~ # TODO: Transform the data structure tests into the mock-response tests.
# TODO tests: (normal serving + proxying) * (learning santiagi + not learning)
A host/listener (B) trusts proxied requests according to the minimum trust #
in the request. If the request comes from an untrusted proxy or is for an # Proxying
untrusted client, B ignores it. # ~~~~~~~~
#
""" # A host/listener (B) trusts proxied requests according to the minimum trust
def setUp(self): # in the request. If the request comes from an untrusted proxy or is for an
super(SantiagoTest, self).setUp() # untrusted client, B ignores it.
#
self.serveOnPort(9000) # """
# def setUp(self):
def test_acknowledgement(self): # super(SantiagoTest, self).setUp()
"""If B receives an authorized request, then it replies with a location. #
# self.serveOnPort(9000)
An "authorized request" in this case is for a service from a client that #
B is willing to host that service for. # def test_acknowledgement(self):
# """If B receives an authorized request, then it replies with a location.
In this case, B will answer with the wiki's location. #
# An "authorized request" in this case is for a service from a client that
""" # B is willing to host that service for.
self.santiago_b.receive(from_="a", to="b", #
client="a", host="b", # In this case, B will answer with the wiki's location.
service="wiki", reply_to=None) #
# """
self.assertEqual(self.santiago_b.outgoing_messages, # self.santiago_b.receive(from_="a", to="b",
[{"from": "b", # client="a", host="b",
"to": "a", # service="wiki", reply_to=None)
"client": "a", #
"host": "b", # self.assertEqual(self.santiago_b.outgoing_messages,
"service": "wiki", # [{"from": "b",
"locations": ["192.168.0.13"], # "to": "a",
"reply-to": "localhost:8000"}]) # "client": "a",
# "host": "b",
def test_reject_bad_service(self): # "service": "wiki",
"""Does B reject requests for unsupported services? # "locations": ["192.168.0.13"],
# "reply-to": "localhost:8000"}])
In this case, B should reply with an empty list of locations. #
# def test_reject_bad_service(self):
""" # """Does B reject requests for unsupported services?
self.santiago_b.receive(from_="a", to="b", #
client="a", host="b", # In this case, B should reply with an empty list of locations.
service="wiki", reply_to=None) #
# """
self.assertEqual(self.santiago_b.outgoing_messages, # self.santiago_b.receive(from_="a", to="b",
[{"from": "b", # client="a", host="b",
"to": "a", # service="wiki", reply_to=None)
"client": "a", #
"host": "b", # self.assertEqual(self.santiago_b.outgoing_messages,
"service": "wiki", # [{"from": "b",
"locations": [], # "to": "a",
"reply-to": "localhost:8000"}]) # "client": "a",
# "host": "b",
def test_reject_bad_key(self): # "service": "wiki",
"""If B receives a request from an unauthorized key, it does not reply. # "locations": [],
# "reply-to": "localhost:8000"}])
An "unauthorized request" in this case is for a service from a client #
that B does not trust. This is different than clients B hosts no # def test_reject_bad_key(self):
services for. # """If B receives a request from an unauthorized key, it does not reply.
#
In this case, B will never answer the request. # An "unauthorized request" in this case is for a service from a client
# that B does not trust. This is different than clients B hosts no
""" # services for.
self.santiago_b.receive(from_="a", to="b", #
client="z", host="b", # In this case, B will never answer the request.
service="wiki", reply_to=None) #
# """
self.assertEqual(self.santiago_b.outgoing_messages, []) # self.santiago_b.receive(from_="a", to="b",
# client="z", host="b",
def test_reject_good_source_bad_client(self): # service="wiki", reply_to=None)
"""B is silent when a trusted key proxies anything for an untrusted key. #
# self.assertEqual(self.santiago_b.outgoing_messages, [])
B doesn't know who the client is and should consider it an #
untrusted key connection attempt. # def test_reject_good_source_bad_client(self):
# """B is silent when a trusted key proxies anything for an untrusted key.
""" #
self.santiago_b.receive(from_="a", to="b", # B doesn't know who the client is and should consider it an
client="z", host="b", # untrusted key connection attempt.
service="wiki", reply_to=None) #
# """
self.assertEqual(self.santiago_b.outgoing_messages, []) # self.santiago_b.receive(from_="a", to="b",
# client="z", host="b",
def test_reject_bad_source_good_client(self): # service="wiki", reply_to=None)
"""B is silent when an untrusted key proxies anything for a trusted key. #
# self.assertEqual(self.santiago_b.outgoing_messages, [])
B doesn't know who the proxy is and should consider it an #
untrusted key connection attempt. # def test_reject_bad_source_good_client(self):
# """B is silent when an untrusted key proxies anything for a trusted key.
""" #
self.santiago_b.receive(from_="z", to="b", # B doesn't know who the proxy is and should consider it an
client="a", host="b", # untrusted key connection attempt.
service="wiki", reply_to=None) #
# """
self.assertEqual(self.santiago_b.outgoing_messages, []) # self.santiago_b.receive(from_="z", to="b",
# client="a", host="b",
def test_reject_bad_source_bad_client(self): # service="wiki", reply_to=None)
"""B is silent when untrusted keys proxy anything for untrusted keys. #
# self.assertEqual(self.santiago_b.outgoing_messages, [])
B doesn't know who anybody is and considers this an untrusted #
connection attempt. # def test_reject_bad_source_bad_client(self):
# """B is silent when untrusted keys proxy anything for untrusted keys.
""" #
self.santiago_b.receive(from_="y", to="b", # B doesn't know who anybody is and considers this an untrusted
client="z", host="b", # connection attempt.
service="wiki", reply_to=None) #
# """
self.assertEqual(self.santiago_b.outgoing_messages, []) # self.santiago_b.receive(from_="y", to="b",
# client="z", host="b",
def test_learn_santaigo(self): # service="wiki", reply_to=None)
"""Does B learn new Santiago locations from trusted requests? #
# self.assertEqual(self.santiago_b.outgoing_messages, [])
If A sends B a request with a new Santiago location, B should learn it. #
# def test_learn_santaigo(self):
""" # """Does B learn new Santiago locations from trusted requests?
self.santiago_b.receive(from_="a", to="b", #
client="a", host="b", # If A sends B a request with a new Santiago location, B should learn it.
service="wiki", reply_to="localhost:9001") #
# """
self.assertEqual(self.santiago_b.consuming["santiago"]["a"], # self.santiago_b.receive(from_="a", to="b",
["localhost:9000", "localhost:9001"]) # client="a", host="b",
# service="wiki", reply_to="localhost:9001")
def test_handle_requests_once(self): #
"""Verify that we reply to each request only once.""" # self.assertEqual(self.santiago_b.consuming["santiago"]["a"],
# ["localhost:9000", "localhost:9001"])
self.santiago_b.receive(from_="a", to="b", #
client="a", host="b", # def test_handle_requests_once(self):
service="wiki", reply_to=None) # """Verify that we reply to each request only once."""
self.santiago_b.process() #
# self.santiago_b.receive(from_="a", to="b",
self.assertEqual(self.santiago_b.outgoing_messages, []) # client="a", host="b",
# service="wiki", reply_to=None)
class TestServerInitialResponse(SantiagoTest): # self.santiago_b.process()
pass #
# self.assertEqual(self.santiago_b.outgoing_messages, [])
class TestClientInitialResponse(SantiagoTest): #
pass # class TestServerInitialResponse(SantiagoTest):
# pass
class TestForwardedRequest(SantiagoTest): #
pass # class TestClientInitialResponse(SantiagoTest):
# pass
class TestForwardedResponse(SantiagoTest): #
pass # class TestForwardedRequest(SantiagoTest):
# pass
class TestSimpleSantiago(unittest.TestCase): #
def setUp(self): # class TestForwardedResponse(SantiagoTest):
# pass
port_a = "localhost:9000" #
port_b = "localhost:8000" # class TestSimpleSantiago(unittest.TestCase):
# def setUp(self):
listeners_a = {"http": {"port": port_a}} #
senders_a = ({ "protocol": "http", "proxy": tor_proxy_port },) # port_a = "localhost:9000"
# port_b = "localhost:8000"
listeners_b = {"http": {"port": port_b}} #
senders_b = ({ "protocol": "http", "proxy": tor_proxy_port },) # listeners_a = {"http": {"port": port_a}}
# senders_a = ({ "protocol": "http", "proxy": tor_proxy_port },)
hosting_a = { "b": { "santiago": set( ["aDifferentHexNumber.onion"])}} #
consuming_a = { "santiagao": {"b": set(["iAmAHexadecimalNumber.onion"])}} # listeners_b = {"http": {"port": port_b}}
# senders_b = ({ "protocol": "http", "proxy": tor_proxy_port },)
hosting_b = { "a": { "santiago": set( ["iAmAHexadecimalNumber.onion"])}} #
consuming_b = { "santiagao": { "a": set( ["aDifferentHexNumber.onion"])}} # hosting_a = { "b": { "santiago": set( ["aDifferentHexNumber.onion"])}}
# consuming_a = { "santiagao": {"b": set(["iAmAHexadecimalNumber.onion"])}}
self.santiago_a = SimpleSantiago(listeners_a, senders_a, #
hosting_a, consuming_a, "a") # hosting_b = { "a": { "santiago": set( ["iAmAHexadecimalNumber.onion"])}}
self.santiago_b = SimpleSantiago(listeners_b, senders_b, # consuming_b = { "santiagao": { "a": set( ["aDifferentHexNumber.onion"])}}
hosting_b, consuming_b, "b") #
# self.santiago_a = santiago.Santiago(listeners_a, senders_a,
cherrypy.Application(self.santiago_a, "/") # hosting_a, consuming_a, "a")
cherrypy.Application(self.santiago_b, "/") # self.santiago_b = santiago.Santiago(listeners_b, senders_b,
# hosting_b, consuming_b, "b")
cherrypy.engine.start() #
# cherrypy.Application(self.santiago_a, "/")
def testRequest(self): # cherrypy.Application(self.santiago_b, "/")
self.santiago_a.request(from_="a", to="b", #
client="a", host="b", # cherrypy.engine.start()
service="wiki", reply_to="localhost:9000") #
# def testRequest(self):
# self.santiago_a.request(from_="a", to="b",
class Unwrapping(unittest.TestCase): # client="a", host="b",
# service="wiki", reply_to="localhost:9000")
def testVerifySigner(self): #
pass #
# class Unwrapping(unittest.TestCase):
def testVerifyClient(self): #
pass # def testVerifySigner(self):
# pass
def testDecryptClient(self): #
pass # def testVerifyClient(self):
# pass
class IncomingProxyRequest(unittest.TestCase): #
# def testDecryptClient(self):
"""Do we correctly handle valid, incoming, proxied messages? # pass
#
These tests are for the first wrapped layer of the message, that which is # class IncomingProxyRequest(unittest.TestCase):
signed by the sender. The sender is not necessarily the original requester #
who's asking us to do something with the message. # """Do we correctly handle valid, incoming, proxied messages?
#
# These tests are for the first wrapped layer of the message, that which is
# signed by the sender. The sender is not necessarily the original requester
# who's asking us to do something with the message.
#
# """
#
# def setUp(self):
# pass
#
# def testPassingMessage(self):
# """Does a valid proxied message pass?"""
#
# pass
#
# def testInvalidSig(self):
# """Does an invalid signature raise an error?"""
#
# pass
#
# def testUnknownClient(self):
# """Does an unknown client raise an error?"""
#
# pass
#
# class IncomingSignedRequest(IncomingProxyRequest):
#
# """Do we correctly handle valid, incoming, messages?
#
# These tests focus on the second layer of the message which is signed by the
# host/client and lists a destination.
#
# """
# def testProxyOtherHosts(self):
# """Messages to others are sent to them directly or proxied."""
#
# pass
#
# def testHandleMyHosting(self):
# """Messages to me are not proxied and handled normally."""
#
# pass
#
# def testNoDestination(self):
# """Messages without destinations are ignored."""
#
# pass
#
# class IncomingRequestBody(IncomingSignedRequest):
#
# """Do we correctly handle the body of a request?
#
# This is the last layer of the message which is encrypted by the original
# sender. This validation also depends on the previous layer's data, making
# it a bit more complicated.
#
# """
# def testHandleGoodMessage(self):
# """Sanity check: no errors are thrown for a valid message."""
#
# pass
#
# def testCantDecryptMessage(self):
# """This message isn't for me. I can't decrypt it."""
#
# pass
#
# def testImNotHost(self):
# """Bail out if someone else is the host, yet I am the "to"."""
#
# pass
#
# def testImNotClient(self):
# """Bail out if someone else is the client, yet I am the "to"."""
#
# pass
#
# def testHostAndClient(self):
# """Bail out if the message includes a host and a client.
#
# A circular response?
#
# """
# pass
#
# def testImNotTo(self):
# """This message isn't for me.
#
# The "To" has been repeated from the signed message, but I'm not the
# recipient in the encrypted message.
#
# """
# pass
#
# def testNoDestinations(self):
# """No host, client, or to."""
#
# pass
#
# def testSignersDiffer(self):
# """The signed message and encrypted message have different signers."""
#
# pass
#
# def testSignerAndClientDiffer(self):
# """The encrypted message is signed by someone other than the cilent."""
#
# pass
class VerifySender(test_pgpprocessor.MessageWrapper):
"""Santiago.verify_sender performs as expected.
It must unwrap the message and return the message's (decrypted) body. If
stuff is weird about the message, raise errors:
- Raise an InvalidSignature error when the signature is incorrect.
- Raise an UnwillingHost error when the signer is not a client authorized to
send us Santiago messages.
""" """
def setUp(self): def setUp(self):
pass super(VerifySender, self).setUp()
def testPassingMessage(self): self.santiago = santiago.Santiago(
"""Does a valid proxied message pass?""" hosting = { self.keyid: {"santiago": ["1"] }},
me = self.keyid)
self.method = "verify_sender"
pass self.unwrapper = pgpprocessor.Unwrapper(str(self.messages[2]))
def testInvalidSig(self): def test_valid_message(self):
"""Does an invalid signature raise an error?""" """A valid message (correctly signed and from a trusted host) passes."""
pass gpg_data = getattr(self.santiago, self.method)(self.unwrapper)
def testUnknownClient(self): self.assertEqual(self.messages[1], gpg_data.message)
"""Does an unknown client raise an error?"""
pass def test_fail_invalid_signature(self):
"""A message with an invalid signature fails
class IncomingSignedRequest(IncomingProxyRequest): It raises an InvalidSignature error.
"""Do we correctly handle valid, incoming, messages?
These tests focus on the second layer of the message which is signed by the
host/client and lists a destination.
"""
def testProxyOtherHosts(self):
"""Messages to others are sent to them directly or proxied."""
pass
def testHandleMyHosting(self):
"""Messages to me are not proxied and handled normally."""
pass
def testNoDestination(self):
"""Messages without destinations are ignored."""
pass
class IncomingRequestBody(IncomingSignedRequest):
"""Do we correctly handle the body of a request?
This is the last layer of the message which is encrypted by the original
sender. This validation also depends on the previous layer's data, making
it a bit more complicated.
"""
def testHandleGoodMessage(self):
"""Sanity check: no errors are thrown for a valid message."""
pass
def testCantDecryptMessage(self):
"""This message isn't for me. I can't decrypt it."""
pass
def testImNotHost(self):
"""Bail out if someone else is the host, yet I am the "to"."""
pass
def testImNotClient(self):
"""Bail out if someone else is the client, yet I am the "to"."""
pass
def testHostAndClient(self):
"""Bail out if the message includes a host and a client.
A circular response?
""" """
pass message = self.unwrapper.message.splitlines(True)
message[7] += "q"
self.unwrapper.message = "".join(message)
def testImNotTo(self): self.assertRaises(InvalidSignatureError,
"""This message isn't for me. getattr(self.santiago, self.method), self.unwrapper)
The "To" has been repeated from the signed message, but I'm not the def test_fail_invalid_signer(self):
recipient in the encrypted message. """A message with a valid signature from an untrusted signer fails.
It raises an UntrustedClient error.
""" """
pass self.santiago.hosting = { 1: { "santiago": ["1"] }}
def testNoDestinations(self): self.assertRaises(UnwillingHostError,
"""No host, client, or to.""" getattr(self.santiago, self.method), self.unwrapper)
class VerifyClient(VerifySender):
"""Santiago.verify_client performs as expected.
It must unwrap the message and return the message's (decrypted) body. If
stuff is weird about the message, raise errors:
- Raise an InvalidSignature error when the signature is incorrect.
- Raise an UnwillingHost error when the signer is not a client authorized to
send us Santiago messages.
Is this just unnecessarily fucking complicating all of this? Yes. Screw
proxying, just get it out the door by sending the encrypted bits directly.
"""
def setUp(self):
super(VerifyClient, self).__init__()
self.method = "verify_client"
def test_proxy_request(self):
"""When the message is for somebody else, it gets proxied."""
pass pass
def testSignersDiffer(self): def test_return_only_valid_message(self):
"""The signed message and encrypted message have different signers.""" """Invalid messages (without "to" and "request" keys) return nothing."""
pass pass
def testSignerAndClientDiffer(self): def test_dont_verify_source(self):
"""The encrypted message is signed by someone other than the cilent.""" """If the message is being proxied, we don't care who sent the message.
"""
pass pass
def show(name, item, iterations=1): def show(name, item, iterations=1):
@ -465,4 +559,5 @@ def show(name, item, iterations=1):
pprint(item) pprint(item)
if __name__ == "__main__": if __name__ == "__main__":
logging.disable(logging.CRITICAL)
unittest.main() unittest.main()