2017-03-05 22:21:08 +00:00
|
|
|
# Client-to-Client Protocol
|
|
|
|
|
|
|
|
Wormhole clients do not talk directly to each other (at least at first): they
|
|
|
|
only connect directly to the Rendezvous Server. They ask this server to
|
|
|
|
convey messages to the other client (via the `add` command and the `message`
|
|
|
|
response). This document explains the format of these client-to-client
|
|
|
|
messages.
|
|
|
|
|
|
|
|
Each such message contains a "phase" string, and a hex-encoded binary "body".
|
|
|
|
|
2017-11-25 18:44:20 +00:00
|
|
|
Any phase which is purely numeric (`^\d+$`) is reserved for encrypted
|
|
|
|
application data. The Rendezvous server may deliver these messages multiple
|
|
|
|
times, or out-of-order, but the wormhole client will deliver the
|
|
|
|
corresponding decrypted data to the application in strict numeric order. All
|
|
|
|
other (non-numeric) phases are reserved for the Wormhole client itself.
|
|
|
|
Clients will ignore any phase they do not recognize.
|
2017-03-05 22:21:08 +00:00
|
|
|
|
|
|
|
Immediately upon opening the mailbox, clients send the `pake` phase, which
|
|
|
|
contains the binary SPAKE2 message (the one computed as `X+M*pw` or
|
|
|
|
`Y+N*pw`).
|
|
|
|
|
|
|
|
Upon receiving their peer's `pake` phase, clients compute and remember the
|
2017-03-05 23:55:07 +00:00
|
|
|
shared key. They derive the "verifier" (a hash of the shared key) and deliver
|
|
|
|
it to the application by calling `got_verifier`: applications can display
|
|
|
|
this to users who want additional assurance (by manually comparing the values
|
|
|
|
from both sides: they ought to be identical). At this point clients also send
|
|
|
|
the encrypted `version` phase, whose plaintext payload is a UTF-8-encoded
|
|
|
|
JSON-encoded dictionary of metadata. This allows the two Wormhole instances
|
|
|
|
to signal their ability to do other things (like "dilate" the wormhole). The
|
|
|
|
version data will also include an `app_versions` key which contains a
|
|
|
|
dictionary of metadata provided by the application, allowing apps to perform
|
|
|
|
similar negotiation.
|
|
|
|
|
|
|
|
At this stage, the client knows the supposed shared key, but has not yet seen
|
|
|
|
evidence that the peer knows it too. When the first peer message arrives
|
|
|
|
(i.e. the first message with a `.side` that does not equal our own), it will
|
2017-04-06 20:52:26 +00:00
|
|
|
be decrypted: we use authenticated encryption (`nacl.SecretBox`), so if this
|
|
|
|
decryption succeeds, then we're confident that *somebody* used the same
|
|
|
|
wormhole code as us. This event pushes the client mood from "lonely" to
|
|
|
|
"happy".
|
2017-03-05 23:55:07 +00:00
|
|
|
|
|
|
|
This might be triggered by the peer's `version` message, but if we had to
|
|
|
|
re-establish the Rendezvous Server connection, we might get peer messages out
|
|
|
|
of order and see some application-level message first.
|
|
|
|
|
|
|
|
When a `version` message is successfully decrypted, the application is
|
|
|
|
signaled with `got_version`. When any application message is successfully
|
|
|
|
decrypted, `received` is signaled. Application messages are delivered
|
|
|
|
strictly in-order: if we see phases 3 then 2 then 1, all three will be
|
|
|
|
delivered in sequence after phase 1 is received.
|
|
|
|
|
|
|
|
If any message cannot be successfully decrypted, the mood is set to "scary",
|
2017-04-06 20:52:26 +00:00
|
|
|
and the wormhole is closed. All pending Deferreds will be errbacked with a
|
|
|
|
`WrongPasswordError` (a subclass of `WormholeError`), the nameplate/mailbox
|
|
|
|
will be released, and the WebSocket connection will be dropped. If the
|
|
|
|
application calls `close()`, the resulting Deferred will not fire until
|
|
|
|
deallocation has finished and the WebSocket is closed, and then it will fire
|
|
|
|
with an errback.
|
2017-03-05 22:21:08 +00:00
|
|
|
|
|
|
|
Both `version` and all numeric (app-specific) phases are encrypted. The
|
2017-04-06 20:52:26 +00:00
|
|
|
message body will be the hex-encoded output of a NaCl `SecretBox`, keyed by a
|
2017-03-05 22:21:08 +00:00
|
|
|
phase+side -specific key (computed with HKDF-SHA256, using the shared PAKE
|
|
|
|
key as the secret input, and `wormhole:phase:%s%s % (SHA256(side),
|
|
|
|
SHA256(phase))` as the CTXinfo), with a random nonce.
|