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.
- 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.
Part of Receipt cryptography and standards
The two lifetimes
The mistake underneath most rotation outages is treating a key as having one lifetime. It has two.
| Phase | Duration | What it means |
|---|---|---|
| Signing lifetime | Weeks to months | The key is used to produce new signatures |
| Verification lifetime | The full retention period | The 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.
| Behaviour | Consequence |
|---|---|
| Accept unverified | The control is bypassed by making the key endpoint unreachable |
| Reject everything | An availability incident for a network problem |
| Use the cached set, reject unknown key ids | Correct — 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.
- A compromised key must stop being accepted immediately — there is no overlap window.
- Signatures it made before the compromise may still be valid, and distinguishing them requires knowing when the compromise began.
- That is what a signed revocation entry with an effective timestamp provides: signatures before this moment remain valid, after it do not.
- 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
| Phase | Duration | Meaning |
|---|---|---|
| Signing lifetime | Weeks to months | The key produces new signatures |
| Verification lifetime | The full retention period | The 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
- Publish the new key before signing with it. For longer than the slowest verifier's cache.
- Carry signing windows in the key set. So a signature dated outside its key's window is detectable.
- Never remove a verification key inside the retention period. Removing it invalidates every signature it made.
- 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.
Sources and further reading
- RFC 7517 — JSON Web Key
- NIST SP 800-57 Part 1 Rev. 5 — Key Management
- RFC 8037 — CFRG elliptic curve signatures for JOSE
- Published operational guidance on key rotation in distributed systems.