mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-09-19 04:59:01 +00:00
Built out request unwrapping. Now I need to wrap outgoing ones.
- Added request diagram. - Renamed a couple things.
This commit is contained in:
parent
75c33bf84e
commit
4399b579ca
@ -36,6 +36,43 @@ We also don't:
|
|||||||
proxies)
|
proxies)
|
||||||
:TODO: move to santiago.py, merge the documentation.
|
:TODO: move to santiago.py, merge the documentation.
|
||||||
|
|
||||||
|
Each request is built like the following. Parenthesized items are inferred from
|
||||||
|
context and not included explicitly. Bracketed items are lists. The initial
|
||||||
|
request is a signed message whose source is inferred from the message's
|
||||||
|
signature, while the destination assumed to be the recipient. That message
|
||||||
|
contains another signed message with two parts: an intended recipient and an
|
||||||
|
encrypted request. That encrypted request contains the important details, like
|
||||||
|
the requested host or client, the service, where the replies go, and any service
|
||||||
|
locations::
|
||||||
|
|
||||||
|
Request -----+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
/--------------------------\
|
||||||
|
| Signed Data (A) |
|
||||||
|
| |
|
||||||
|
| (From: X) |
|
||||||
|
| (To: Y) |
|
||||||
|
| (Request)---+ |
|
||||||
|
| | |
|
||||||
|
| v |
|
||||||
|
+--------------------------+
|
||||||
|
| Signed Data (B) |
|
||||||
|
| |
|
||||||
|
| (From: A) |
|
||||||
|
| To: B |
|
||||||
|
| Request:----+ |
|
||||||
|
| | |
|
||||||
|
| v |
|
||||||
|
+--------------------------+
|
||||||
|
| Encrypted Data (C) |
|
||||||
|
| |
|
||||||
|
| Host/Client: B |
|
||||||
|
| Service: C |
|
||||||
|
| Reply To: [A1, A2] |
|
||||||
|
| Locations: [B1] |
|
||||||
|
\--------------------------/
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import cfg
|
import cfg
|
||||||
@ -148,7 +185,7 @@ class SimpleSantiago(object):
|
|||||||
|
|
||||||
logging.debug("Santiago started!")
|
logging.debug("Santiago started!")
|
||||||
|
|
||||||
def am_i(self, server):
|
def i_am(self, server):
|
||||||
"""Verify whether this server is the specified server."""
|
"""Verify whether this server is the specified server."""
|
||||||
|
|
||||||
return self.me == server
|
return self.me == server
|
||||||
@ -243,7 +280,9 @@ class SimpleSantiago(object):
|
|||||||
try:
|
try:
|
||||||
request = self.unpack_request(kwargs)
|
request = self.unpack_request(kwargs)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
self.proxy(kwargs)
|
return
|
||||||
|
|
||||||
|
if not request:
|
||||||
return
|
return
|
||||||
|
|
||||||
logging.debug("Unpacked request: ", str(request))
|
logging.debug("Unpacked request: ", str(request))
|
||||||
@ -286,50 +325,98 @@ class SimpleSantiago(object):
|
|||||||
are the only folks who must trust the inner signature. Proxiers must
|
are the only folks who must trust the inner signature. Proxiers must
|
||||||
only verify that signature.
|
only verify that signature.
|
||||||
|
|
||||||
XXX: if we duplicate any keys in the signed message (for addressing)
|
FIXME: If we duplicate any keys in the signed message (for addressing)
|
||||||
they could (should?) be overwritten by the contents of the
|
they must be ignored.
|
||||||
encrypted message.
|
|
||||||
|
|
||||||
TODO: Do we use "to" or "host" the plain-text inner signature? If we
|
|
||||||
use "host", we'll need to use "client" on the way back, but that
|
|
||||||
feels like it gives up far too much information.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
request = PgpUnwrapper(str(kwargs["request"]), gpg=self.gpg)
|
request = PgpUnwrapper(str(kwargs["request"]), gpg=self.gpg)
|
||||||
|
|
||||||
request = self.verify_sender(request)
|
proxied_request = self.verify_sender(request)
|
||||||
|
encrypted_body = dict(self.verify_client(request))
|
||||||
|
|
||||||
if not request:
|
if not encrypted_body:
|
||||||
return
|
return
|
||||||
|
|
||||||
request = self.verify_client(request)
|
if not self.i_am(encrypted_body["to"]):
|
||||||
|
self.proxy(proxied_request)
|
||||||
if not request:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# TODO this stuff.
|
request_body = dict(self.decrypt_client(request))
|
||||||
if not self.am_i(dict(str(request))["host"]):
|
|
||||||
self.proxy(request)
|
if not request_body:
|
||||||
return
|
return
|
||||||
|
|
||||||
request = self.decrypt_client(request)
|
# we could proxy misdirected requests here, but I'm not.
|
||||||
|
if not (self.i_am(request_body["to"]) and
|
||||||
if not request:
|
self.i_am(request_body["host"])):
|
||||||
|
# self.proxy(proxied_request)
|
||||||
return
|
return
|
||||||
|
|
||||||
# TODO this stuff.
|
return request_body
|
||||||
if not self.am_i(dict(str(request))["host"]):
|
|
||||||
self.proxy(request)
|
|
||||||
return
|
|
||||||
|
|
||||||
return request
|
|
||||||
|
|
||||||
def verify_sender(self, request):
|
def verify_sender(self, request):
|
||||||
"""Verify the signature of the message's sender.
|
"""Verify the signature of the message's sender.
|
||||||
|
|
||||||
|
This is part (A) in the message diagram.
|
||||||
|
|
||||||
Raises an InvalidSignature error when the signature is incorrect.
|
Raises an InvalidSignature error when the signature is incorrect.
|
||||||
|
|
||||||
TODO Raises an UntrustedClient error when the signer is not a client
|
Raises an UnwillingHost error when the signer is not a client
|
||||||
|
authorized to send us Santiago messages.
|
||||||
|
|
||||||
|
At this point (the initial unwrap) request.next() returns a signed
|
||||||
|
message body that contains, but isn't, the request's body.
|
||||||
|
|
||||||
|
We're verifying the Santiago message sender to make sure the proxier is
|
||||||
|
allowed to send us messages.
|
||||||
|
|
||||||
|
"""
|
||||||
|
proxied_request = request.next()
|
||||||
|
|
||||||
|
if not request.gpg.valid:
|
||||||
|
raise InvalidSignatureError()
|
||||||
|
|
||||||
|
if not self.get_host_locations(request.gpg.fingerprint, "santiago"):
|
||||||
|
raise UnwillingHostError(
|
||||||
|
"{0} is not a Santiago client.".format(request.gpg.fingerprint))
|
||||||
|
|
||||||
|
return proxied_request
|
||||||
|
|
||||||
|
def verify_client(self, request):
|
||||||
|
"""Verify the signature of the message's source.
|
||||||
|
|
||||||
|
This is part (B) in the message diagram.
|
||||||
|
|
||||||
|
Raises an InvalidSignature error when the signature is incorrect.
|
||||||
|
|
||||||
|
Raises an UnwillingHost error when the signer is not a client authorized
|
||||||
|
to send us Santiago messages.
|
||||||
|
|
||||||
|
We shouldn't verify the Santiago client here, it the request goes to
|
||||||
|
somebody else.
|
||||||
|
|
||||||
|
:FIXME: Handle weird requests. what if the client isn't the encrypter??
|
||||||
|
|
||||||
|
"""
|
||||||
|
encrypted_body = request.next()
|
||||||
|
|
||||||
|
if not request.gpg.valid:
|
||||||
|
raise InvalidSignatureError()
|
||||||
|
|
||||||
|
if not self.get_host_locations(request.gpg.fingerprint, "santiago"):
|
||||||
|
raise UnwillingHostError(
|
||||||
|
"{0} is not a Santiago client.".format(request.gpg.fingerprint))
|
||||||
|
|
||||||
|
return encrypted_body
|
||||||
|
|
||||||
|
def decrypt_client(self, request):
|
||||||
|
"""Decrypt the message and validates the encrypted signature.
|
||||||
|
|
||||||
|
This is part (C) in the message diagram.
|
||||||
|
|
||||||
|
TODO Raises an InvalidSignature error when the signature is incorrect.
|
||||||
|
|
||||||
|
TODO Raises an UnwillingHost error when the signer is not a client
|
||||||
authorized to send us Santiago messages.
|
authorized to send us Santiago messages.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -339,46 +426,11 @@ class SimpleSantiago(object):
|
|||||||
raise InvalidSignatureError()
|
raise InvalidSignatureError()
|
||||||
|
|
||||||
if not self.get_host_locations(request.gpg.fingerprint, "santiago"):
|
if not self.get_host_locations(request.gpg.fingerprint, "santiago"):
|
||||||
raise UntrustedClientError(
|
raise UnwillingHostError(
|
||||||
"{0} is not trusted.".format(request.gpg.fingerprint))
|
"{0} is not a Santiago client.".format(request.gpg.fingerprint))
|
||||||
|
|
||||||
if not self.get_client_locations(request_body["to"], "santiago"):
|
|
||||||
self.proxy(request_body)
|
|
||||||
return
|
|
||||||
|
|
||||||
return request_body
|
return request_body
|
||||||
|
|
||||||
def verify_client(self, request):
|
|
||||||
"""Verify the signature of the message's source.
|
|
||||||
|
|
||||||
Raises an InvalidSignature error when the signature is incorrect.
|
|
||||||
|
|
||||||
TODO Raises an UntrustedClient error when the signer is not a client
|
|
||||||
authorized to send us Santiago messages.
|
|
||||||
|
|
||||||
"""
|
|
||||||
request.next()
|
|
||||||
|
|
||||||
def decrypt_client(self, request):
|
|
||||||
"""Decrypt the message and validates the encrypted signature.
|
|
||||||
|
|
||||||
TODO Raises an InvalidSignature error when the signature is incorrect.
|
|
||||||
|
|
||||||
TODO Raises an UntrustedClient error when the signer is not a client
|
|
||||||
authorized to send us Santiago messages.
|
|
||||||
|
|
||||||
pre::
|
|
||||||
|
|
||||||
self.me == request["host"]
|
|
||||||
|
|
||||||
post::
|
|
||||||
|
|
||||||
False not in map(("host", "client", "service", "locations",
|
|
||||||
"reply_to"), request.__haskey__)
|
|
||||||
|
|
||||||
"""
|
|
||||||
request.next()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def signed_contents(request):
|
def signed_contents(request):
|
||||||
"""Return the contents of the signed message.
|
"""Return the contents of the signed message.
|
||||||
@ -414,7 +466,7 @@ class SimpleSantiago(object):
|
|||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.am_i(host):
|
if not self.i_am(host):
|
||||||
self.proxy(to, host, client, service, reply_to)
|
self.proxy(to, host, client, service, reply_to)
|
||||||
else:
|
else:
|
||||||
self.learn_service(client, "santiago", reply_to)
|
self.learn_service(client, "santiago", reply_to)
|
||||||
@ -451,10 +503,10 @@ class SimpleSantiago(object):
|
|||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.am_i(to):
|
if not self.i_am(to):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.am_i(client):
|
if not self.i_am(client):
|
||||||
self.proxy()
|
self.proxy()
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -524,7 +576,7 @@ class SignatureError(Exception):
|
|||||||
class InvalidSignatureError(SignatureError):
|
class InvalidSignatureError(SignatureError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class UntrustedClientError(SignatureError):
|
class UnwillingHostError(SignatureError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user