mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-06 03:28:24 +00:00
The freshness check measured a signal's age with a saturating subtraction, which yields zero for any timestamp ahead of the local clock, so the age test could not fail for a future-dated signal and no other term bounded the issue time from above. A signal claiming to be issued arbitrarily far in the future was accepted as strictly fresh. That voided the property that the freshness window is narrower than the session-id replay window, leaving the replay cache as the sole defence against a captured offer being replayed. Tolerate forward-dating only up to the same 60s of clock skew already allowed in the other direction, and report the skew outcome for a signal accepted under that grace, so the existing clock-skew log fires for a peer whose clock is ahead just as it does for one whose clock is behind. Stop trusting the declared expiry beyond the issue time plus the configured TTL, so a sender cannot widen its own acceptance window by inflating that field. A single timestamp is now acceptable over at most the signalling TTL plus 60s on each side, 240s under the shipped defaults. Log the traversal signals refused as dated in the future A signal refused as future-dated left nothing behind naming the skew that caused it, so a peer with a badly wrong clock and a peer forging timestamps looked the same from a log. Record the rejection with the observed skew, and keep the accepted-within-tolerance case at debug so an ordinary clock drift does not produce warnings. As with the sibling filter on this path, counters would need metrics wiring this subsystem does not have, so this is logging only. Truncate a peer-supplied session id on a character boundary short_id sliced by byte index, which panics when the boundary falls inside a multi-byte character, and the session id it is given comes straight from a remote party's JSON with no charset validation anywhere ahead of it. The panic was latent while every call sat inside a tracing field, since the field expression is not evaluated when the level is filtered out, and where it was evaluated it sat inside a per-offer task whose unwind went nowhere. The logging added in the previous commit calls it eagerly in the notify loop itself, which makes it reachable at the default log level and fatal to that loop: one gift-wrapped offer carrying a non-ascii session id would have ended all traversal signalling for the life of the process, with no log line and nothing to restart it. Truncate by characters instead. The test drives the exact input that panics; with the byte slice restored it reproduces the original panic.