Skip to content

[auto-rotation feature] feat(rekey): Manual rotation for all key types + test vectors#969

Merged
Manuthor merged 3 commits into
docs/key-autorotation-specfrom
feat/key-rotation-manual
May 29, 2026
Merged

[auto-rotation feature] feat(rekey): Manual rotation for all key types + test vectors#969
Manuthor merged 3 commits into
docs/key-autorotation-specfrom
feat/key-rotation-manual

Conversation

@Manuthor
Copy link
Copy Markdown
Contributor

Summary

Implements manual key rotation (Re-Key) for symmetric keys, including the three-phase wrapping-key rotation that re-wraps all dependent wrapped keys atomically.

This is PR 2 of 5 in the key auto-rotation feature stack (depends on PR 1: #968):

develop
  ← PR 1  docs/key-autorotation-spec   (#968)
  ← PR 2  feat/key-rotation-manual      ← this PR
  ← PR 3  feat/key-rotation-scheduler
  ← PR 4  feat/key-rotation-notifications
  ← PR 5  feat/key-rotation-ui

What's included

Core operation — crate/server/src/core/operations/rekey.rs

  • rekey() — top-level KMIP Re-Key handler
  • Plain symmetric key rotation: fresh key material, new UUID, ReplacementObjectLink / ReplacedObjectLink chain
  • Wrapping-key rotation (Phase 1 + Phase 2):
    • Phase 1: generate and persist the new wrapping key immediately (committed, so it is available for re-wrapping)
    • Phase 2: iterate all Active keys whose WrappingKeyLink points to the old wrapping key, unwrap each with the old key, re-wrap with the new key, update WrappingKeyLink
  • Wrapped-key rotation: unwrap in memory → generate fresh plaintext → re-wrap with the same wrapping key → store under new UUID

Database — ObjectsStore additions

  • find_wrapped_by(wrapping_key_uid) — returns all Active keys wrapped by a given UID (SQLite, PostgreSQL, MySQL backends)

Rotation metadata

  • x-rotate-generation incremented on the new key
  • x-rotate-date set to rotation timestamp on the new key
  • x-rotate-interval set to 0 on the old key (disables future auto-rotation on it); inherited on the new key
  • Manual rekey intentionally does not inherit x-rotate-interval on the new key (operator must re-arm explicitly — see spec)

Test vectors

New vectors under test_data/vectors/ covering:

  • Plain symmetric key rotation
  • Wrapping key rotation (with dependant re-wrap verification)
  • Wrapped key rotation
  • KMIP link chain integrity after two successive rotations

Breaking changes

None. Re-Key was already a KMIP 2.1 operation; this PR completes its implementation.

Reviewer notes

  • The two-phase wrapping-key rotation is the most complex part. Phase 1 is committed inside a single DB transaction; Phase 2 re-wrapping is done per-dependant key. A crash between phases is safe: the old wrapping key remains valid and no dependant key has been orphaned.
  • The x-rotate-interval = 0 on the old key after manual rekey is intentional — see the attribute table in the spec (PR 1).

- Implement KMIP ReKey for symmetric keys with name transfer per §4.4
- Support re-wrapping dependent keys when a wrapping key is rekeyed
- Add find_wrapped_by() to ObjectsStore trait (SQLite, PostgreSQL, MySQL)
- Fix: transfer Name attribute from old to new key during ReKey
- Fix: error on self-wrap when wrapping_key_id is user-supplied
- Fix: bypass ownership check for server-configured KEK

Tested with 37 vector tests (9 symmetric + 27 keypair + 1 security)
@Manuthor Manuthor changed the title feat(rekey): implement symmetric key ReKey with wrapping key re-wrap [auto-rotation feature] feat(rekey): implement symmetric key ReKey with wrapping key re-wrap May 28, 2026
@Manuthor Manuthor changed the title [auto-rotation feature] feat(rekey): implement symmetric key ReKey with wrapping key re-wrap [auto-rotation feature] feat(rekey): Manual rotation for all key types + test vectors May 29, 2026
@Manuthor Manuthor merged commit 6cc8ce5 into docs/key-autorotation-spec May 29, 2026
57 of 59 checks passed
@Manuthor Manuthor deleted the feat/key-rotation-manual branch May 29, 2026 12:57
Manuthor added a commit that referenced this pull request May 29, 2026
…s + test vectors (#969)

* feat(rekey): implement symmetric key ReKey with wrapping key re-wrap

- Implement KMIP ReKey for symmetric keys with name transfer per §4.4
- Support re-wrapping dependent keys when a wrapping key is rekeyed
- Add find_wrapped_by() to ObjectsStore trait (SQLite, PostgreSQL, MySQL)
- Fix: transfer Name attribute from old to new key during ReKey
- Fix: error on self-wrap when wrapping_key_id is user-supplied
- Fix: bypass ownership check for server-configured KEK

Tested with 37 vector tests (9 symmetric + 27 keypair + 1 security)

* fix: consolidate rekey operations using trait

* feat: consolidate Recertify operation
Manuthor added a commit that referenced this pull request May 31, 2026
…s + test vectors (#969)

* feat(rekey): implement symmetric key ReKey with wrapping key re-wrap

- Implement KMIP ReKey for symmetric keys with name transfer per §4.4
- Support re-wrapping dependent keys when a wrapping key is rekeyed
- Add find_wrapped_by() to ObjectsStore trait (SQLite, PostgreSQL, MySQL)
- Fix: transfer Name attribute from old to new key during ReKey
- Fix: error on self-wrap when wrapping_key_id is user-supplied
- Fix: bypass ownership check for server-configured KEK

Tested with 37 vector tests (9 symmetric + 27 keypair + 1 security)

* fix: consolidate rekey operations using trait

* feat: consolidate Recertify operation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant