mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 11:08:25 +00:00
A link rekey msg1 carries nothing that ties it to one cycle. A copy taken off the wire still decrypts as the peer in the peer's current epoch after the cycle it started has ended, and once the new link session is past the 30 s floor it classified as a fresh rekey. Replayed from any address the transport accepts handshakes on, or from the peer's own, it armed a responder pending that refused the peer's genuine rekeys and suppressed this node's own trigger until the 120 s hold retired it, and one replay per hold kept link key rotation stopped. The msg2 also went to the address the msg1 came from, so anyone holding a copy could have the node send a msg2 to an address of their choosing: a reflection, 69 bytes out for 114 in. The responder's per-peer record of answered msg1s, which already kept the answer that armed the pending it holds, now keeps the digest of each answered msg1 once its cycle ends, whether the pending was adopted, retired or abandoned. A msg1 matching an ended cycle is refused before it can arm a pending, and before the dual-initiation tie-break, so a copy cannot make this node abandon its own rekey either. Retention is bounded at the 256 most recent ended cycles per peer, at most 8 KiB: at least two hours of the peer's cycles, and eight and a half at the default 120 s interval when the message-count trigger does not fire first. A msg1 from an older cycle of the same peer epoch is not recognized. The record lives with the peering, so it starts empty when the peering forms again while the peer's epoch is unchanged, after this node restarts or the link is torn down and re-formed; a msg1 captured before that still arms a pending. Closing either gap needs a field in msg1 that orders cycles, which is a wire change. A test that replays across a re-formed peering records the second residual and is ignored. The rekey msg2 now goes to the peer's established link, as the resend of a lost msg2 already did, through one helper both arms use. When the peer has no established link the msg1 is refused, as a failed send already was. A peer whose address changed and whose first frame from the new address is a rekey msg1 is answered at the old address; the next authenticated frame from the new address moves the link, and the initiator's resends reach it there. The msg2 stored at link setup, resent for a duplicate setup msg1 inside the 30 s after a cutover, likewise goes to the established link rather than to the msg1's source; a genuine duplicate comes from the address the peering was formed with, so a peer whose setup msg2 was lost sees no change. The responder's pending index is registered under the transport the msg2 was sent on rather than the one the msg1 arrived on. Otherwise a msg1 that came in on another transport left an index entry retirement never removed, and the peer's first frame on the new session found no session under its index, so the responder could not promote. Tests run a genuine link rekey to completion while keeping its msg1, then replay it from an address the node has no link with, from the peer's own address, and from an earlier cycle than the latest, and probe both the peer's next rekey and the node's own trigger. The aged two-node link setup moves out of the held-msg2 builder so both use it, and the peer gains a test-only seam to backdate its rekey dampening.