Skip to content

Let a warden sign a new policy for an enclave-sealed key - #1125

Merged
kwsantiago merged 1 commit into
mainfrom
enclave-policy-updates
Oct 28, 2026
Merged

kwsantiago merged 1 commit into
mainfrom
enclave-policy-updates

Conversation

@kwsantiago

@kwsantiago kwsantiago commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Lets a warden sign a new policy for an enclave-sealed key, without the key leaving the enclave.

  • EnvelopeEncryption::encrypt_for_enclave_with_warden seals a key with a warden's BIP340 public key and epoch 0, both bound into the blob's policy hash under a new domain (keep-enclave-policy-v2). Blobs sealed without a warden open as before and keep their policy.
  • New UpdateSealedPolicy request and SealedKey response, both appended last. The enclave checks the warden's signature over the whole old blob and the new policy's hash at the next epoch, then seals the key again under the blob's own data key, with a nonce derived from that key and the new body.
  • The running enclave keeps its policy. The new blob applies after a restart imports it.
  • Host helpers: Warden, sealed_policy_hash, policy_update_message, EnclaveClient::update_sealed_policy. The mock refuses the request.
  • docs/ENCLAVE.md explains the flow and that this is not rollback protection: the old blob still opens to its old policy.

Testing

  • Enclave tests (124) and keep-enclave-host tests
  • New tests: an update reseals for the next launch; replaying it gives the same blob; the old blob still opens to its old policy; refused when unsigned, truncated, signed for another epoch, signed for another blob, or sealed without a warden; a loaded key sealed the same way is left alone; an empty policy is refused
  • Known-answer test for the warden hashes, identical in both crates and checked independently; both crates pin the new wire digest
  • Mutation checks on every new branch; workspace clippy and fmt

Summary by CodeRabbit

  • New Features
    • Warden-protected sealed keys can now receive signed policy updates and be resealed under the new policy. The updated key takes effect when imported after an enclave restart; existing sealed blobs remain usable.
    • Added documentation covering policy updates, restart behavior, and limitations.

A sealed enclave policy could not change without sealing the key again from its plaintext outside the enclave. A key can now be sealed with a warden: encrypt_for_enclave_with_warden puts the warden's BIP340 public key and an epoch, starting at 0, in the sealed body and in the hash the blob is bound to, under a new domain so a blob with a warden and one without can never pass for each other. Blobs sealed without a warden open as before and keep their policy.

UpdateSealedPolicy carries a blob, a new policy and the warden's signature over the whole blob and the new policy's hash at the next epoch. The enclave checks both, seals the key again inside the enclave under the blob's own data key, with a nonce derived from that key and the new body so the same move always gives the same blob, and returns it as SealedKey. The running enclave keeps its policy, since blobs sealed alike share a hash whatever key they hold; the new policy applies after a restart imports the new blob.

This is not rollback protection: the old blob still opens to its old policy, so the loosest policy a warden ever signed bounds the key. docs/ENCLAVE.md says so. Both crates pin the new wire digest and a known answer for the warden hashes.
@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ad836369-f8fd-4ae1-b2fc-bf8da210c271
Commits

Reviewing files that changed from the base of the PR and between b173156 and d7d5116.

Files selected for processing: 8
  • docs/ENCLAVE.md
  • keep-enclave/enclave/src/kms.rs
  • keep-enclave/enclave/src/vsock_server.rs
  • keep-enclave/host/src/client.rs
  • keep-enclave/host/src/kms.rs
  • keep-enclave/host/src/lib.rs
  • keep-enclave/host/src/mock.rs
  • keep-enclave/host/src/protocol.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The change adds optional warden metadata to sealed wallet blobs and a signed policy-update operation. The host sends the blob, new policy, and signature to the enclave, which verifies the update and returns a resealed blob. Documentation describes epoch handling, restart behavior, and update limitations.

Changes

Warden-authorized sealed policy updates

Layer / File(s) Summary
Warden-bound blob format
keep-enclave/host/src/kms.rs, keep-enclave/enclave/src/kms.rs
Host and enclave KMS code add warden keys and epochs to sealed blobs, bind policy hashes to that metadata, and parse both warden-bound and existing policy-only blobs. Tests add hash vectors and cover sealing and opening.
Enclave policy update flow
keep-enclave/enclave/src/kms.rs, keep-enclave/enclave/src/vsock_server.rs, keep-enclave/host/src/protocol.rs
The protocol adds update request and sealed-key response variants. The enclave checks the policy, warden signature, and epoch before resealing the wallet. Tests cover successful updates and rejected inputs; wire-format samples and digests are updated.
Host API and usage documentation
keep-enclave/host/src/client.rs, keep-enclave/host/src/mock.rs, keep-enclave/host/src/lib.rs, docs/ENCLAVE.md
The host client sends update requests and returns resealed blobs. The mock returns an internal error for updates. Public exports and documentation include the warden helpers and update procedure.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant EnclaveClient
  participant EnclaveRequest
  participant vsock_server
  participant EnclaveKms
  EnclaveClient->>EnclaveRequest: Send UpdateSealedPolicy with blob, policy, and signature
  EnclaveRequest->>vsock_server: Dispatch update request
  vsock_server->>EnclaveKms: Verify signature and reseal wallet
  EnclaveKms-->>vsock_server: Return updated encrypted wallet
  vsock_server-->>EnclaveClient: Return SealedKey
Loading

Possibly related PRs

  • privkeyio/keep#1110: Introduced policy-bound EncryptedWallet blobs and a policy-returning decrypt API, which this change extends with warden and epoch metadata.
  • privkeyio/keep#1123: Uses the same EncryptedWallet policy-opening path that this change extends with optional warden metadata.

Suggested reviewers: wksantiago

Merge Risk: Minimal · up to d7d51

No actionable issue remains from this review; the policy-update change is mergeable after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: allowing a warden to authorize a new policy for an enclave-sealed key.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 22 functions across 7 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

I’m a rabbit with a policy to renew,
I hop with a signed blob, epoch two.
The enclave checks the seal,
Then sends the key anew.
I nibble clover, pleased and true.

Comment @coderabbitai help to get the list of available commands.

@kwsantiago
kwsantiago merged commit a3a13e2 into main Oct 28, 2026
13 checks passed
@kwsantiago
kwsantiago deleted the enclave-policy-updates branch October 28, 2026 19:57
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