Manav.id
Compliance · 4 min read

Rotating signing keys without breaking verification

Rotating signing keys without breaking verification

Rotation is a security requirement and an operational hazard. The failure is always the same shape: a signer moves to a new key faster than verifiers learn about it, and everything in between fails.

How do you rotate a signing key without breaking verification?

Publish before you sign. Rotation outages happen because the signer moves to a new key faster than verifiers refresh their cached key set, and the window is bounded by the slowest verifier's cache — which the issuer does not control and usually does not know.

Key takeaways
  • Signing and verification have asymmetric lifetimes: a key stops signing long before it stops needing to verify.
  • An overlap window where the new key is published before it signs removes the propagation race entirely.
  • Retiring a verification key invalidates every historical signature it made, which is why audit keys are never retired.

The two lifetimes

Phase 1: publish B, sign with Aoverlaplonger than any cachePhase 2: cut over to Bevery verifier knows Bno racePhase 3: keep A for verificationretention periodnever removed
Publishing before signing removes the race rather than shortening it.

The mistake underneath most rotation outages is treating a key as having one lifetime. It has two.

PhaseDurationWhat it means
Signing lifetimeWeeks to monthsThe key is used to produce new signatures
Verification lifetimeThe full retention periodThe key must remain available to check old signatures

For session tokens the second can be short, because nobody verifies a token from last year. For audit records it is the retention period, which may be a decade.

Why rotation breaks things

# The race
  t0   issuer rotates to key B, begins signing with it
  t0   key set published with A and B
  t0+  verifiers have a cached key set containing only A
       → signatures from B fail until the cache expires

# Cache TTLs vary. Some verifiers refresh on failure,
# many do not. Some are offline. Some are other companies.

The window is bounded by the longest cache TTL among verifiers, which the issuer does not control and often does not know.

The overlap window

Publish before signing. The sequence removes the race rather than shortening it.

# Phase 1  — publish, do not sign
  key set: [A (active), B (published, not signing)]
  duration: longer than the longest verifier cache TTL

# Phase 2  — cut over
  key set: [A (retired for signing), B (active)]
  new signatures use B; every verifier already knows B

# Phase 3  — keep A for verification
  key set: [A (verify only), B (active)]
  duration: the retention period. A is never removed.

Phase one duration is the design decision. It must exceed the slowest verifier's refresh interval, and if you do not know what that is, the answer is longer than you think.

What the published key set should carry

{
  "keys": [
    { "kid": "2026-03-a", "kty": "OKP", "crv": "Ed25519",
      "x": "...", "use": "sig",
      "status": "verify_only",
      "signing_from": "2025-09-01",
      "signing_until": "2026-03-01" },
    { "kid": "2026-03-b", "kty": "OKP", "crv": "Ed25519",
      "x": "...", "use": "sig",
      "status": "active",
      "signing_from": "2026-03-01" }
  ]
}

The signing window fields let a verifier check that a signature was made while its key was active. A signature dated outside its key's window is suspicious independently of whether it verifies.

Failing closed without failing open in practice

A verifier that cannot fetch the key set has a choice, and the usual implementation quietly picks wrong.

BehaviourConsequence
Accept unverifiedThe control is bypassed by making the key endpoint unreachable
Reject everythingAn availability incident for a network problem
Use the cached set, reject unknown key idsCorrect — known keys still work, unknown ones fail

The third row requires a durable cache rather than an in-memory one, so a restart during an outage does not empty it. That detail is where implementations usually fail.

Compromise is different from rotation

Planned rotation is graceful. Compromise is not, and conflating them produces a bad design.

  1. A compromised key must stop being accepted immediately — there is no overlap window.
  2. Signatures it made before the compromise may still be valid, and distinguishing them requires knowing when the compromise began.
  3. That is what a signed revocation entry with an effective timestamp provides: signatures before this moment remain valid, after it do not.
  4. Without that distinction, a compromise invalidates every historical signature the key made, which for an audit key means losing the evidence.

Point four is the argument for planning compromise handling before it happens. An organisation that revokes an audit signing key without an effective-time boundary has destroyed its own records.

Two lifetimes, not one

Signing and verification are different clocks
PhaseDurationMeaning
Signing lifetimeWeeks to monthsThe key produces new signatures
Verification lifetimeThe full retention periodThe key must remain available

Treating a key as having one lifetime is the mistake underneath most rotation outages, and underneath the worse failure of retiring a key that still needs to verify a decade of records.

Objections and honest limits

“Our verifiers refresh on failure.” Some do. Some are offline, some are other companies, and some cache for a day. The overlap window has to accommodate the slowest one you do not know about.

“Compromise is just faster rotation.” It is not. Compromise has no overlap window, and it needs an effective-time boundary so signatures made before it remain valid. Without that, revoking an audit key destroys your own records.

Rotating safely

  1. Publish the new key before signing with it. For longer than the slowest verifier's cache.
  2. Carry signing windows in the key set. So a signature dated outside its key's window is detectable.
  3. Never remove a verification key inside the retention period. Removing it invalidates every signature it made.
  4. Use a durable cache and reject unknown key ids. So a restart during an outage does not empty it.

Terms used here

Overlap window
The period a new key is published but not yet signing, which removes the propagation race.
Signing window
The interval during which a key was active, carried in the key set so out-of-window signatures are detectable.
Effective-time revocation
Revoking from a specific moment, so earlier signatures survive a compromise.

Frequently asked questions

Why do rotation outages happen? The signer moves to a new key faster than verifiers refresh their cached key set. The window is bounded by the slowest verifier's TTL, which the issuer does not control.

How long should the overlap window be? Longer than the longest verifier cache TTL. If you do not know what that is, longer than you think.

When can a verification key be removed? For audit records, never within the retention period. Removing it invalidates every historical signature it made.

How is compromise different from rotation? There is no overlap window. You need a signed revocation with an effective timestamp so signatures before the compromise remain valid.

Where this fits in Manav

Manav's receipt is deliberately small: RFC 8785 canonicalisation, one signature algorithm, keys published at a well-known URL, and a verifier short enough to audit or reimplement.

Read the architecture →

Sources and further reading