Files
simplexmq/spec/modules/Simplex/FileTransfer/Client.md
Evgeny @ SimpleX Chat 1cc4d98dd0 terms 2
2026-03-13 17:56:14 +00:00

3.0 KiB

Simplex.FileTransfer.Client

XFTP client: connection management, handshake, data packet upload/download with forward secrecy.

Source: FileTransfer/Client.hs

Non-obvious behavior

1. ALPN-based handshake version selection

getXFTPClient checks the ALPN result after TLS negotiation:

  • xftpALPNv1 or httpALPN11: performs v1 handshake with key exchange (httpALPN11 is used for web port connections)
  • No ALPN or unrecognized: uses legacy v1 transport parameters without handshake

2. Router certificate chain validation

xftpClientHandshakeV1 validates the router's identity by checking that the CA fingerprint from the certificate chain matches the expected keyHash from the router address. The router signs an authentication public key (X25519) with its long-term key. The client verifies this signature against the certificate chain, then extracts the X25519 key for HMAC-based command authentication. This authentication key is distinct from the per-download ephemeral DH keys.

3. Ephemeral DH key pair per download

downloadXFTPChunk generates a fresh X25519 key pair for each data packet download. The public key is sent with the FGET command; the router returns its own ephemeral key. The derived shared secret encrypts the data packet in transit. This provides forward secrecy — compromising a past DH key doesn't decrypt other downloads.

4. Size-proportional download timeout

downloadXFTPChunk calculates the timeout as baseTimeout + (sizeInKB * perKbTimeout), where baseTimeout is the base TCP timeout and perKbTimeout is a per-kilobyte timeout from the network config. Larger data packets get proportionally more time. This prevents premature timeouts on large data packets over slow connections.

5. prepareChunkSizes threshold algorithm

prepareChunkSizes selects data packet sizes using a 75% threshold: if the remaining payload exceeds 75% of the next larger size, it uses the larger size. Otherwise, it uses the smaller size. singleChunkSize returns Just size only if the payload fits in a single data packet (used for redirect files which must be single-packet).

6. Upload sends data packet after command block

uploadXFTPChunk sends the FPUT command and data packet body in the same streaming HTTP/2 request: the protocol command block is sent first, followed immediately by the raw encrypted data via hSendFile. The command result (FROk or error) is received only after both the command and data have been fully sent. This is a single HTTP/2 round trip, not a two-phase interaction.

7. Empty corrId as nonce

sendXFTPCommand uses "" (empty bytestring) as the correlation ID for all commands. XFTP is strictly request-response within a single HTTP/2 stream, so correlation IDs are unnecessary. The empty value is passed to C.cbNonce to produce a constant nonce for command authentication (HMAC/signing), not encryption — XFTP authenticates commands but does not encrypt them within the TLS tunnel.