- 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 (<store>.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
3.4 KiB
3.4 KiB
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 staticSHA-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-inputnow holduser:$fastsync$1$pbkdf2-sha256$<iters>$<salt>$<stored_key>$<server_key>(PBKDF2-HMAC-SHA256, default 600000 iterations, range 100000–10000000). The legacyuser:SHA256HEXform is hard-rejected; there is no auto-upgrade. Generate stores offline withfastsync-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<store>.dummykeysidecar (atomic publish, exact mode 0600) so challenges are stable across restarts. - Verified transport for auth-required modules. A module with
auth usersaccepts credentials only over verified TLS whose client certificate matches--client-cn, or — when--allow-unauthenticatedis explicitly set — plaintext from a loopback peer. Remote plaintext is refused before any challenge. Clients must use--tlsto send--password-filecredentials to a non-loopback daemon;--client-cnis 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:
-KTOCTOU-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-inputchecks, log-injection escaping, and lazy protocol debug escaping.
Added
fastsync-server --hash-credentials FILE [--iterations N]offline tool.<store>.dummykeysidecar (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 itsSTATUS_OK. A 2.19.0 client and a 2.18.0 server (or vice versa) fail cleanly at the handshake. - Daemon modules declaring
auth usersrequire 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 for the flag-parity matrix.