# 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`