Skip to content

Instantly share code, notes, and snippets.

@lgrahl
Last active May 6, 2019 09:31
Show Gist options
  • Save lgrahl/bc5a715b835e82ecc4fcea8d0443e420 to your computer and use it in GitHub Desktop.
Save lgrahl/bc5a715b835e82ecc4fcea8d0443e420 to your computer and use it in GitHub Desktop.
SaltyRTC v2

SaltyRTC v2

Rationale for Changes

  • Why send the cookie all the time? It's known after the initial message towards the other peer.
  • Make sending application data more efficient (v1 requires embedding data into a msgpack object).
  • Allow chunking of data (designed for but not limited to application data).
  • Design application data to not suffer from head-of-line blocking by using a stream identifier along with chunking.
    • Unsolved so far: This requires a flow control that is carefully designed to prevent filling its send buffer too much. It may even require its own acknowledgement protocol in order to do so.
  • Allow group communication of up to 65534 participants.
  • Get rid of the initiator and responder role.

To Do & Discuss Topics

  • Spec: This is not only a signalling protocol. It's also a way to exchange arbitrary data over an end-to-end encrypted transport.
  • Spec: Do we want to separate SaltyRTC WebSocket Transport and SaltyRTC Protocol?
  • Spec: Do we want to replace MessagePack with FlatBuffers or the like?
  • Feature: Do we want task chaining?
  • Speed: Do we want (optional) 0-RTT support? Ideally, this would skip all client-to-server and all client-to-client messages (at least for 1-to-1 communication) and there would be only one RTT for the client's 'auth' messages. It could be done by negotiating a session id for both server and client.
  • Speed: RTT implications of sending two messages after another from the same source. Should these be avoided?
  • Speed: Chunk-then-encrypt, rather than encrypt-then-chunk?
  • Speed: Use little endian instead of big endian?
  • Security: Implications of having a secret key in a QR code instead of public key || token.
  • Security: DoS protection is gone as path cleaning isn't possible anymore
  • Security: Can we encrypt the header as well?
  • Instead of cookie being an optional part of the header, 'server-hello' and 'client-hello' could contain a cookie field and before 'key' there could be an unencrypted 'cookie' message. Depends on the outcome of RTT implications of sending two messages after another from the same source.
  • Should we keep the 3xxx range of close codes or go for the 4xxx range? If we stay at 3xxx, we need to register our close codes at the IANA WebSocket Protocol Registries

Crypto

  • Use (the original or the IETF variant of) the AEAD ChaCha20-Poly1305 construction or libsodium's AEAD XChaCha20-Poly1305 construction. This allows us to have additional authenticated data that does not need to be part of the nonce, nor does it need to be encrypted.
  • Clients use a shared permanent secret key (which is an implicit token) instead of permanent public/private key pairs.
  • Clients use an ephemeral key pair towards the server.

Path

The path is a hash of the permanent secret key.

Header

  • Flags:

    • C: Cookie included (between sequence number and data)
    • E: End-of-message (message is now complete)
    • A: Application data
  • Stream is the stream identifier (for application data but could also be used for parallel tasks)

  • First 8 bytes are additionally authenticated data with AEAD cipher

  • Nonce := Sequence Number || Cookie.

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |C|E|A|R|R|R|R|R|     DUNNO     |            Stream             |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |            Source             |          Destination          |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                        Sequence Number                        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                                                               |
    |                            Cookie                             |
    |                                                               |
    |                                                               |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                             Data                          ...
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    

Messages

Client-to-Server

  • Set the cookie field in the header for 'server-hello' and 'client-hello'
  • Always use 'client-hello'.
  • List of connected clients in 'server-auth'
  • 'new-client' announces that a new client is connected
  • 'new-initiator', 'new-responder' and 'drop-responder' are gone
  • For 'send-error', split the fields id into source, destination and sequence_number

Client-to-Client

  • Set the cookie field in the header for the 'key' message
  • Clients send the 'key' message directly (async) which is encrypted by the shared permanent secret key.
  • The client with the lower assigned identity is called the controlling client, the other one the controlled client.
  • 'auth' is sent with the tasks field by the controlled client first, then 'auth' is sent with the task field by the controlling client.
  • 'token' message is gone
@lgrahl
Copy link
Author

lgrahl commented Oct 31, 2018

Something we should also consider is the complexity of a flow control for forwarding to arbitrary clients. This could easily result in deadlocks.

And another thing: QUIC could be an interesting transport since it supports multiple streams out of the box.

@lgrahl
Copy link
Author

lgrahl commented May 6, 2019

A peer should:

  • discard messages from the server that contain an invalid header, nonce, crypto errors, ... before decryption but treat them as protocol errors when data inside the already decrypted and authenticated (!) payload is invalid.
  • same as above for messages from other clients but since the peer is authenticated, not only discard messages but also ignore the other client until the server announces that the other client has disconnected.

Rationale: In v1, it is possible to connect to a path and trigger protocol errors that force the clients to close their connections. When not using WebSocket with TLS, it is also possible to fake WebSocket packets that trigger a protocol error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment