From bbb8bc475593b9ff481ec214c4391fe6aff854f4 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Sun, 21 Jun 2020 22:32:27 +0200 Subject: WIP secure transport using libsodium secretstream --- protocol_transport.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 protocol_transport.md (limited to 'protocol_transport.md') diff --git a/protocol_transport.md b/protocol_transport.md new file mode 100644 index 0000000..7915e29 --- /dev/null +++ b/protocol_transport.md @@ -0,0 +1,128 @@ +# tomsg transport protocol + +This is the specification for the lower-level transport protocol that underlies +the application-level protocol described in `protocol.md`. This transport is +used for communication between a client and the server. + +If at any point one of the parties breaks the protocol, the socket and transport +should be closed. + +## Size assumptions + +The protocol makes a few assumptions about lengths of certain values in the +libsodium API. An implementation of the protocol should verify that these +assumptions still hold when the application is finally run. + +- `crypto_secretstream_xchacha20poly1305_KEYBYTES` = 32 +- `crypto_secretstream_xchacha20poly1305_HEADERBYTES` = 24 +- `crypto_kx_SESSIONKEYBYTES` >= 32 +- `crypto_kx_PUBLICKEYBYTES` = 32 +- `crypto_kx_SECRETKEYBYTES` = 32 + +## Message types + +- ClientHello: + - 16 bytes magic: `tomsg v01 client` + - 32 bytes client public key +- ServerHello: + - 16 bytes magic: `tomsg v01 server` + - 32 bytes server public key + - 24 bytes server->client libsodium secretstream header +- ClientHello2: + - 8 bytes magic: `cheader0` + - 24 bytes client->server libsodium secretstream header +- DataMessage: + - 8 bytes magic: `datamsg0` + - 8 bytes (unsigned little-endian) message length = N + - N bytes data + +## Initialisation sequence + +### Client initialisation sequence + +The following handshake is performed in order to set up two libsodium +secretstreams, one for client->server communication (a push stream) and one for +server->client communication (a pull stream). + +1. Generate a keypair using `crypto_kx_keypair`. These keys are referred to as + the client public and secret keys. +2. Send a ClientHello message. +3. Receive a ServerHello message. + - Check that the magic is correct for this version of the transport protocol. + - Use `crypto_kx_client_session_keys` to compute the client->server and + server->client encryption keys. + - Use `crypto_secretstream_xchacha20poly1305_init_push` to create the + client->server libsodium push secretstream using the client->server + encryption key. + - Use `crypto_secretstream_xchacha20poly1305_init_pull` to create the + server->client libsodium pull secretstream using the server->client + encryption key and header. +4. Send a ClientHello2 message. + +### Server initialisation sequence + +The following handshake is performed in order to set up two libsodium +secretstreams, one for server->client communication (a push stream) and one for +client->server communication (a pull stream). + +1. Generate a keypair using `crypto_kx_keypair`. These keys are referred to as + the server public and secret keys. +2. Receive a ClientHello message. + - Check that the magic is correct for this version of the transport protocol. + - Use `crypto_kx_server_session_keys` to compute the client->server and + server->client symmetric keys. + - Use `crypto_secretstream_xchacha20poly1305_init_push` to create the + server->client libsodium push secretstream using the server->client + encryption key. +3. Send a ServerHello message. +4. Receive a ClientHello2 message. + - Check that the magic is correct for this version of the transport protocol. + - Use `crypto_secretstream_xchacha20poly1305_init_pull` to create the + client->server libsodium pull secretstream using the client->server + encryption key and header. + +## Data exchange + +At this point, we can reconcile the two halves of the protocol: both parties now +have a push secretstream for transmission to the other party, and a pull +secretstream for reception from the other party. + +### Receiving a message + +At all times, the current party can receive a DataMessage message. To handle the +message, use `crypto_secretstream_xchacha20poly1305_pull` to decrypt the +encrypted data in the message, and observe the tag. +- If the tag is 0: + - Return the decrypted data to the application. +- If the tag is `crypto_secretstream_xchacha20poly1305_TAG_FINAL`: + - Close the socket and consider the transport closed. Report this to the + application. + +### Sending a message + +When the current party wants to send a message, use +`crypto_secretstream_xchacha20poly1305_push`, with no additional data and +`tag` = 0, to encrypt the message in the push secretstream. Then send the +encrypted result in a DataMessage message to the other party. + +### Ending the transport + +When the current party wants to end the transport and close the socket, one has +a choice between a graceful shutdown and an improper shutdown (just closing the +socket and forgetting about the connection). Sometimes an improper shutdown +cannot be avoided, e.g. if the application is killed by the operating system, +but a graceful shutdown is always preferred. + +To perform a graceful shutdown, use `crypto_secretstream_xchacha20poly1305_push` +on the push secretstream to encrypt the empty string with no additional data and +`tag` = `crypto_secretstream_xchacha20poly1305_TAG_FINAL`. Then send the +encrypted result in a DataMessage message to the other party. + +After the DataMessage message is successfully sent, the socket can be closed and +the transport considered ended. + + +# SSH notes + +- Use libssh, not libssh2 +- `ssh_message.type` has type `enum ssh_requests_e`, not `int` -- cgit v1.2.3-70-g09d2