From cc27ee1b8354d5c6ca1067f8f097da98760a9dd9 Mon Sep 17 00:00:00 2001 From: TapTap Date: Sat, 12 Sep 2026 20:22:46 +0200 Subject: [PATCH] Release v2.19.0 - Protocol version 2.19.0 (SCRAM-SHA-256 daemon auth replacing the replayable digest) - Salted PBKDF2 verifier store + --hash-credentials; legacy store hard-rejected - Persistent anti-enumeration dummy key (.dummykey) - Verified TLS / opted-in loopback transport required for auth modules - Secret wiping; carried-over hardening from the security phases - Add CHANGELOG.md and set the CMake project version --- CHANGELOG.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- README.md | 4 ++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..bcdf3a4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,65 @@ +# Changelog + +All notable changes to FastSync are documented here. Versions match +`PROTOCOL_VERSION` (printed by `fastsync --version`); the client and server must +run the same version because the handshake is strict. + +## [2.19.0] - 2026-09-12 + +### Security + +- **Daemon authentication rewritten as SCRAM-SHA-256 challenge/response** + (`STATUS_AUTH_CHALLENGE` → `STATUS_AUTH_RESPONSE` → `STATUS_AUTH_OK`/`STATUS_AUTH_FAILED`), + replacing the old replayable static `SHA-256(password)` bearer credential. + Each proof is bound to a fresh per-connection server nonce plus a client + nonce, so a captured response can never be reused. +- **Salted verifier store.** `--password-file`/`--early-input` now hold + `user:$fastsync$1$pbkdf2-sha256$$$$` + (PBKDF2-HMAC-SHA256, default 600000 iterations, range 100000–10000000). The + legacy `user:SHA256HEX` form is hard-rejected; there is no auto-upgrade. + Generate stores offline with `fastsync-server --hash-credentials FILE + [--iterations N]`. +- **Username-enumeration hardening.** Unknown/off-list users are answered with a + dummy verifier whose salt is a deterministic per-username value + (`HMAC-SHA256(dummy_key, username)`), using the store-wide uniform iteration + count and a constant-time full-length membership scan. The dummy key is + persisted in an owner-only `.dummykey` sidecar (atomic publish, exact + mode 0600) so challenges are stable across restarts. +- **Verified transport for auth-required modules.** A module with `auth users` + accepts credentials only over verified TLS whose client certificate matches + `--client-cn`, or — when `--allow-unauthenticated` is explicitly set — + plaintext from a loopback peer. Remote plaintext is refused before any + challenge. Clients must use `--tls` to send `--password-file` credentials to a + non-loopback daemon; `--client-cn` is mandatory with `--tls`. +- **Secret hygiene.** The plaintext password, derived keys, nonces/proofs and + the dummy key are wiped from memory on every path and never logged. +- Carried-over hardening: `-K` TOCTOU-safe directory walk + (`openat(O_NOFOLLOW)` per component), always shell-quoted SSH remote path, + TLS compression/renegotiation disabled, race-free (open-then-`fstat`) + `--password-file`/`--early-input` checks, log-injection escaping, and lazy + protocol debug escaping. + +### Added + +- `fastsync-server --hash-credentials FILE [--iterations N]` offline tool. +- `.dummykey` sidecar (auto-created, owner-only, 0600). +- Integration tests for auth replay rejection, malformed frames, legacy-store + refusal, and the loopback/TLS transport policy; fuzz targets for config + receive and daemon-auth parsing. + +### Changed + +- **Protocol version 2.18.0 → 2.19.0 (breaking).** The config-frame auth block + is now `[present][username]` (digest removed) and the auth challenge/response + frames are interleaved between the config frame and its `STATUS_OK`. A 2.19.0 + client and a 2.18.0 server (or vice versa) fail cleanly at the handshake. +- Daemon modules declaring `auth users` require a configured credential store at + startup (fail closed); operators regenerate stores from plaintext with + `--hash-credentials`. + +### Notes + +- First tagged release. FastSync implements rsync-compatible file + synchronization over TCP and SSH with TLS (OpenSSL), streaming zstd + compression, multithreaded transfers, and incremental sync. See + [RSYNC_COMPAT.md](RSYNC_COMPAT.md) for the flag-parity matrix. diff --git a/CMakeLists.txt b/CMakeLists.txt index 54dafde..3ec3b24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.22) -project(FastFileTransfer) +project(FastFileTransfer VERSION 2.19.0) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_C_STANDARD 11) diff --git a/README.md b/README.md index 8b83ba3..204a19d 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ source/destination model and rsync-style options while adding optional multithreading, streaming zstd compression, chunking, zero-copy TCP transfers, and native TCP/TLS transports. +The release version is FastSync's client/server protocol version (printed by +`fastsync --version`); client and server must match. See +[CHANGELOG.md](CHANGELOG.md) for the history. + The compatibility target is straightforward: - Existing rsync commands should keep the same meaning.