D30: a wait stamp dated after now (a clock that jumped back) is dropped, never a block until that date — the commit's security review; red-proved; unreleased
gates / gates (push) Successful in 2m3s
gates / gates (push) Successful in 2m3s
This commit is contained in:
+3
-1
@@ -15,7 +15,9 @@
|
||||
hard link, then the temp file is renamed OVER `private.key` and the directory fsynced (a power cut or a kill between
|
||||
two renames used to leave no key, or an empty one). `private.key.prev` keeps the FIRST old key (the escrow may hold it);
|
||||
later ones are `private.key.prev.<unix>`, the newest three kept. The once-an-hour bound is saved in `wg/last-rekey`, so
|
||||
an agent restart does not reset it. Tests `TestD30_TwoRotationsKeepTheFirstOldKey`,
|
||||
an agent restart does not reset it; a start or a last re-key dated AFTER now (a clock that jumped back) is dropped,
|
||||
never a block until that date (the commit's own security review). Tests `TestD30_TwoRotationsKeepTheFirstOldKey`,
|
||||
`TestD30_ALastReKeyFromTheFutureDoesNotBlock`,
|
||||
`TestD30_TheHourBoundSurvivesARestart`, red-proved. **Live (felhom.eu `audits/night-2026-10-23/P2-D30/`):** the D30
|
||||
re-key ran on a test box (before these two changes): clock corrected → 15 min → new key registered → the box switched
|
||||
at its next desired-state fetch → a handshake with the new key.
|
||||
|
||||
@@ -65,12 +65,20 @@ func (m *Manager) clockAheadRekeyLocked(ctx context.Context, block *hub.WireWire
|
||||
"future_s", fut, "rekey_after", m.rekeyAfter.String())
|
||||
return false
|
||||
}
|
||||
// A clock that jumps backwards must not stretch either wait (commit security review 2026-10-23 night): a start or a
|
||||
// last re-key stamped AFTER now is from a wrong clock and is dropped — this whole feature exists because clocks jump.
|
||||
if now.Before(m.futureSince) {
|
||||
m.futureSince = now
|
||||
}
|
||||
if now.Sub(m.futureSince) < m.rekeyAfter {
|
||||
return false
|
||||
}
|
||||
if m.lastRekey.IsZero() {
|
||||
m.lastRekey = m.loadLastRekey()
|
||||
}
|
||||
if now.Before(m.lastRekey) {
|
||||
m.lastRekey = time.Time{}
|
||||
}
|
||||
if !m.lastRekey.IsZero() && now.Sub(m.lastRekey) < rekeyMinGap {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -206,3 +206,22 @@ func TestD30_TheHourBoundSurvivesARestart(t *testing.T) {
|
||||
}
|
||||
_ = active
|
||||
}
|
||||
|
||||
// Commit security review 2026-10-23 night: a last re-key saved while the clock ran ahead (a later date than now) must
|
||||
// not block the next re-key until that date. RED-PROOF: with the „lastRekey after now → dropped" guard removed, this
|
||||
// fails — seen failing 2026-10-23 night.
|
||||
func TestD30_ALastReKeyFromTheFutureDoesNotBlock(t *testing.T) {
|
||||
fh := &fakeHub{}
|
||||
m, _, active, _ := testManager(t, fh)
|
||||
pub := establishWG(t, m, active)
|
||||
m.saveLastRekey(time.Unix(hs+2*365*86400, 0)) // written while the clock was two years ahead
|
||||
ctx := context.Background()
|
||||
t0 := int64(hs - 3*3600)
|
||||
at(m, t0)
|
||||
m.Watchdog(ctx, true, testBlock(pub))
|
||||
at(m, t0+16*60)
|
||||
m.Watchdog(ctx, true, testBlock(pub))
|
||||
if localPub(t, m) == pub {
|
||||
t.Fatal("a last re-key dated in the future must not block the re-key")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user