Using Noise Protocol tunnels in Syndicate systems
The Syndicate ecosystem includes a few ways of gluing together dataspaces over a network.
To begin with, there was no authentication or authorization framework involved at all: programs just exchanged assertions and messages using an ancestor of the Syndicate protocol over a plain socket. There was no way of referring to entities/objects/actors at all: Syndicate at this point was data-only. (It turns out this is sufficient for a surprisingly large range of programs!)
Then, I figured out how to use ideas from Macaroons to introduce capabilities on the wire. This allows recovery of session-local object references from long-lived cryptographic names for use in a protocol session. Programs “upgrade” a name like
<ref {oid: a-service, sig: #[JTTGQeYCgohMXW/2S2XH8g]}>
to a real pointer they can use to send assertions and messages to.
Finally, I incorporated the Noise Protocol Framework, making it possible to use Syndicate to open encrypted, authenticated tunnels across untrusted links. The idea is to use a cleartext socket or websocket (or anything else!) to bootstrap communication, and then use assertions and messages related to Noise to open a Noise session across that foundation.
A small example
Here’s a small example from a real system I’m running.
I run a syndicate-server
Docker
container configured with, among
other stanzas, the following service definition (these are fresh random keys, not the ones I’m
using live):
let ?shared = dataspace
let ?sk = #[0LFU4CAWxrz0VVS9nY2uSc7EWJTusZUcOP0HUpkwSkE]
let ?pk = #[Y3NCy2ZPbmaH62fFI0sl0YOZmM7K7PhVTmRFmgCAgVA]
@<connect-using # <-- this is just a comment, really
<route [<ws "ws://LOCATION.TO.MY.SERVER.WEBSOCKET/">]
<noise {service: a-service key: #[Y3NCy2ZPbmaH62fFI0sl0YOZmM7K7PhVTmRFmgCAgVA]}>>
>
<bind <noise { service: a-service, key: $pk, secretKey: $sk }> $shared #f>
Then I can securely access the $shared
dataspace from a remote syndicate-server
instance
using a stanza like this:
? <resolve-path
<route [<ws "ws://LOCATION.TO.MY.SERVER.WEBSOCKET/">]
<noise {service: a-service key: #[Y3NCy2ZPbmaH62fFI0sl0YOZmM7K7PhVTmRFmgCAgVA]}>>
_
_
<accepted ?sharedDs>>
<the-shared-dataspace-is $sharedDs>
A lightly tricky piece of the puzzle is that the
resolve-path
handler isn’t built-in to syndicate-server
yet: for that part, I’m using a tiny node.js
service until I have a chance to implement the resolution
logic
in Rust. Watch this space.