diff --git a/docs/internals/README.md b/docs/internals/README.md index 949d7ab..82447a3 100644 --- a/docs/internals/README.md +++ b/docs/internals/README.md @@ -1 +1,12 @@ -# Internals +# DSFX Internals + +Welcome, friend! You are viewing the DSFX internal documentation. If you want to _use_ +DSFX, you don't need to read this and could head straight to our user-level docs at + + + +If you want to learn how DSFX works inside, here's what we got: + +- [TigerStyle](../TIGER_STYLE.md) is _the_ style guide, and more. This is the philosophy underlining + all the code here! +- [handshake](./handshake.md) is the protocol for establishing a secure connection between two parties. diff --git a/docs/internals/handshake.md b/docs/internals/handshake.md new file mode 100644 index 0000000..cb8f7fb --- /dev/null +++ b/docs/internals/handshake.md @@ -0,0 +1,161 @@ +# Handshake Protocol Documentation + +This document describes the handshake protocol implemented in the DSFX library. The protocol establishes a secure, authenticated channel between two parties over a network connection. It uses a combination of ephemeral Diffie–Hellman key exchange, symmetric encryption, and digital signatures to both derive a shared secret and verify the identities of the communicating parties. + +> Note: The protocol relies on several subcomponents: +> • The key exchange mechanisms (using ECDH with the X25519 curve and HKDF for key derivation) +> • Encryption and decryption using AES-GCM +> • Digital signatures with ED25519 +> • Transport framing using length-prefixed buffers + +## Overview + +The handshake protocol involves two roles: + +- **Initiator (Client):** Starts the handshake, sends its ephemeral public key, performs client authentication, and verifies the server’s signature. +- **Acceptor (Server):** Waits for the client’s initiation, sends its own ephemeral public key, verifies the client’s authentication, and responds with its signed authentication message. + +Both parties, after successful authentication, derive an identical shared secret that is used to secure subsequent communication. + +## Protocol Steps + +### Step 1: Ephemeral Key Exchange + +**Purpose:** +Each party generates an ephemeral ECDH key pair to perform a Diffie–Hellman key exchange. This key exchange enables both parties to derive a shared symmetric key while providing forward secrecy. + +**Actions:** + +- **Initiator:** + + - Generates an ephemeral ECDH key pair. + - Exports its ephemeral public key into a length-prefixed buffer (using the `buffer.NewLenPrefixed` function). + - Sends the ephemeral public key over the connection. + +- **Acceptor:** + - Waits for the client's ephemeral public key. + - Reads and imports the client’s key from the length-prefixed payload (using `buffer.ReadLenPrefixed` and `keyexchange.ImportPublicKey`). + - Generates its own ephemeral key pair. + - Exports its ephemeral public key. + - Sends its ephemeral public key (again using a length-prefixed buffer). + +### Step 2: Shared Secret Derivation + +**Purpose:** +Using the exchanged ephemeral keys, both parties compute a shared secret. This shared secret is derived via ECDH and then processed with HKDF (using SHA-256) to produce a symmetric session key for message encryption. + +**Actions:** + +- Both parties call the `keyexchange.ComputeDHSecret()` method with their private ephemeral key and the other party’s public ephemeral key. +- An AES-GCM ciphersuite is used in the `encryption.Encrypt()` and `encryption.Decrypt()` functions to protect subsequent authentication messages. + +### Step 3: Authentication of Long-Term Identity + +**Purpose:** +To bind the ephemeral keys (used for the session) with each party’s long-term identity (represented by an ED25519 key pair), the protocol uses digital signatures. This step prevents man-in-the-middle attacks by ensuring that both parties are in possession of their respective long-term private keys. + +**Actions (Client/Initiator):** + +1. **Export Signing Keys:** + + - The client exports its long-term public signing key. + - It also exports the server’s public signing key (provided as a parameter to the handshake). + +2. **Build Authentication Message:** + + - A helper function (`buildMessage`) constructs an authentication message that binds the ephemeral keys: + - First, both ephemeral public keys (client and server) are exported. + - The message is built by concatenating these keys and appending a SHA-256 checksum of the concatenated key values. + - Notably, the final authentication message is defined as: + `authMessage = serverEphemeralPublicKey || SHA256(clientEphemeralPublicKey || serverEphemeralPublicKey)` + +3. **Sign the Message:** + + - The client signs the constructed authentication message with its long-term ED25519 private key using the `identity.Sign()` function. + +4. **Encrypt and Send Authentication Data:** + - The client builds a plaintext message that contains: + - Its exported long-term public key. + - Its signature over the authentication message. + - This plaintext is encrypted using the derived session key (from Step 2) via AES-GCM. + - The encrypted block is sent using a length-prefixed transmission. + +**Actions (Server/Acceptor):** + +1. **Receive and Decrypt Client Authentication Message:** + + - The server reads the client’s authentication message (which was sent as a length-prefixed encrypted message). + - It decrypts the message with the derived session key, retrieving: + - The client’s long-term public signing key. + - The client’s signature. + +2. **Build the Authentication Message:** + + - Similarly to the client side, the server constructs an authentication message with the exchanged ephemeral keys using the `buildMessage` function (note the parameter order is reversed). + +3. **Verify the Client’s Signature:** + + - The server verifies the client’s signature against the built authentication message using `identity.Verify()`. + +4. **Sign and Send the Server Authentication Response:** + - The server signs the same authentication message with its own long-term private key. + - It then encrypts the signed message with the derived session key. + - This encrypted signature is sent back to the client as a length-prefixed buffer. + +### Step 4: Finalizing the Handshake + +**Purpose:** +Both parties confirm that the handshake is complete and that the authentication was successful. + +**Actions:** + +- **Acceptor (Server):** After sending its authentication response, the server waits for a final "handshake complete" message from the client. + +- **Initiator (Client):** + + - After verifying the server’s authentication response (by decrypting and checking the server’s signature), the client sends a final handshake completion message. This is a simple length-prefixed payload containing a one-byte flag (0x01). + +- **Both Parties:** + - On reception of this handshake completion message, the handshake process is finalized. + - At this point, both sides share the same derived symmetric session key which will be used for all subsequent encrypted communication. + +## Message Framing and Transport + +All messages (ephemeral keys, authentication messages, handshake completion flag) are transmitted using a length-prefixed framing mechanism. The `buffer` package is responsible for: + +- Prepending a 2-byte big-endian length prefix to each message. +- Reading and validating the length prefix before consuming the payload. + +This ensures that the message boundaries are clearly established over the TCP stream. + +## Security Considerations + +- **Ephemeral Keys:** + The use of ephemeral ECDH keys ensures forward secrecy; even if long-term keys are compromised later, past session keys remain secure. + +- **Authentication Binding:** + By signing a message that binds the ephemeral keys with the long-term identities, the protocol guarantees that the established session is authenticated. Any tampering in the handshake will cause signature verification to fail. + +- **Encryption:** + All sensitive handshake messages (including public keys and signatures) are encrypted with the derived symmetric key using AES-GCM. This mode provides both confidentiality and integrity. + +- **Length Prefixing:** + The fixed-length (2-byte) prefix before each message fragment ensures that only complete messages are processed, reducing the risk of framing errors and injection attacks. + +## Summary of the Handshake Flow + +1. **Initiate (Client):** + - Generate ephemeral DH key and send it. +2. **Accept (Server):** + - Receive client’s ephemeral key. + - Generate its own ephemeral key and send it. +3. **Client Authentication:** + - Client builds and signs an authentication message. + - Encrypts with derived key and sends to the server. +4. **Server Authentication:** + - Server decrypts and verifies the client’s authentication message. + - Signs the same authentication message and sends it back. +5. **Handshake Completion:** + - Client verifies server’s signature. + - Client sends a final “handshake complete” flag. + - Both sides now share the session key for secure communication.