Repository navigation
Seal enclave FROST shares to their policy and hold FROST rounds to it - #1123
Conversation
FROST key packages reached the enclave in the clear through ImportFrostKey, and the FROST rounds checked only that some policy was loaded, so a share signed under whatever policy the host chose, with no rate or time rule applied. ImportEncryptedFrostKey imports a key package sealed with its policy, sharing the opening and policy adoption of ImportEncryptedKey: the first sealed key imported sets the policy and a key sealed to any other is refused. Plaintext ImportFrostKey is refused unless the enclave is built with allow-plaintext-import, like ImportKey. Round 1 judges the policy for the share's group key, round 2 judges it again before making the share and closes a session it refuses, and each share counts against the group key's rate limits. The host's EnclaveRequest listed ImportFrostKey after GetPublicKey while the enclave lists it after ImportEncryptedKey. postcard numbers variants by position, so every request from Sign on decoded as a different one in the enclave. The host now matches, and both crates pin the encoding of one of every request, response and policy rule to the same digest.
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
FROST import protocol and host support keep-enclave/host/src/protocol.rs, keep-enclave/enclave/src/vsock_server.rs, keep-enclave/host/src/client.rs, keep-enclave/host/src/mock.rs |
The protocol adds ImportEncryptedFrostKey. The host client sends the encrypted key and public-key package. Wire-format tests cover representative requests, responses, policies, and networks. |
Sealed key import and policy adoption keep-enclave/enclave/src/signer.rs, keep-enclave/enclave/src/vsock_server.rs, docs/ENCLAVE.md |
The enclave validates sealed data for wallet and FROST imports, adopts the policy after a successful import, and restricts plaintext FROST import to the test-only feature. The signer stores the imported group public key. |
FROST signing policy and session checks keep-enclave/enclave/src/signer.rs, keep-enclave/enclave/src/vsock_server.rs, keep-enclave/enclave/src/policy.rs, docs/ENCLAVE.md |
The enclave checks policy at both signing rounds and records successful shares. The signer associates sessions with group public keys and rejects a changed share. Tests and documentation cover policy enforcement and rate limits. |
Priority:
Estimated code review effort: 4 (Complex) | ~45 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
participant EnclaveClient
participant handle_request
participant EnclaveSigner
participant PolicyEngine
EnclaveClient->>handle_request: Send round-one request
handle_request->>EnclaveSigner: Get group public key
handle_request->>PolicyEngine: Check FROST policy
handle_request->>EnclaveSigner: Open signing session
EnclaveClient->>handle_request: Send round-two request
handle_request->>EnclaveSigner: Get session group public key
handle_request->>PolicyEngine: Recheck FROST policy
alt Policy allows share
handle_request->>EnclaveSigner: Produce share
handle_request->>PolicyEngine: Record successful share
handle_request-->>EnclaveClient: Return share
else Policy refuses share
handle_request->>EnclaveSigner: Drop session
handle_request-->>EnclaveClient: Return refusal
end
Merge Risk: 
Minimal · up to 26cb1
-
This change adds encrypted FROST key import and applies the sealed policy to both signing rounds. No actionable merge-blocking risk was found in the supplied context.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passedFull details: Docstring Coverage
-
Explanation
Docstring coverage is 44.44% 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 18 functions across 6 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.
A rabbit checks the sealed key’s name,
Then guards each signing round the same.
The group key stays beside the share,
A changed one meets a guarded glare.
Success is counted; closed sessions rest,
And carrot crumbs mark policy’s test.
Comment @coderabbitai help to get the list of available commands.
Summary
FROST key packages reached the Nitro enclave in the clear through
ImportFrostKey, and the FROST rounds only checked that some policy was loaded. A share therefore signed under whatever policy the host chose, with no rate or time rule applied.ImportEncryptedFrostKeyimports a key package sealed with its policy in the existingEncryptedWalletformat (the host'sEnvelopeEncryption::encrypt_for_enclavealready seals arbitrary key bytes). Opening and policy adoption are shared withImportEncryptedKey: the first sealed key imported, wallet or FROST, sets the policy, and a key sealed to any other policy is refused. A wallet blob never parses as a key package and a key package is never 32 bytes, so neither kind imports as the other.ImportFrostKeyis refused unless the enclave is built with the test-onlyallow-plaintext-importfeature, likeImportKey.Host and enclave wire format
The host's
EnclaveRequestlistedImportFrostKeyafterGetPublicKey, while the enclave lists it afterImportEncryptedKey. postcard numbers enum variants by position, so every request fromSignon decoded as a different request in the enclave. The host now matches. Both crates encode one of every request, response and policy rule, with extreme integer values, and pin the same SHA-256 digest, so a variant, field or width changed on one side alone fails a test. The new variant is appended last on both sides, and the host client gainsimport_encrypted_frost_key.Docs
docs/ENCLAVE.md describes sealed FROST import, how the rounds are held to the policy, and that a FROST message carries no amount, destination or event kind, so only the rate,
AllowedHoursandBlockWeekendsrules can stop a FROST share.Testing
cargo +1.89.0 test --manifest-path keep-enclave/enclave/Cargo.toml: 104 passed (103 with--features allow-plaintext-import).cargo +1.89.0 test -p keep-enclave-host: passed, including the wire digest.Summary by CodeRabbit