Skip to content

docs: key vendor backend capability matrix, and refuse an unsafe rewrap (CIP-5313) - #1541

Closed
freshtonic wants to merge 61 commits into
james/cip-5312-stash-keyset-create-rewrap-commandsfrom
james/cip-5313-document-key-vendor-backend-trade-offs-capability-matrix
Closed

freshtonic wants to merge 61 commits into
james/cip-5312-stash-keyset-create-rewrap-commandsfrom
james/cip-5313-document-key-vendor-backend-trade-offs-capability-matrix

Conversation

@freshtonic

@freshtonic freshtonic commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Top layer of the CIP-5203 stack. Implements CIP-5313.

  • Capability matrix in the stack-kms-vendor crate docs, linked from stack-kms and every vendor crate. The Go matrix is corrected to match.
  • Docs that had drifted from the code are fixed. This includes ADR-0011's claim that the guest signs the Google JWT, which is false.
  • Updated: the skills/stash-zerokms section, the stash-cli rewrap text, the CLI README stash keyset section, AGENTS.md and SECURITY.md.
  • Fix: a rewrap to a different vendor key under wrapped data keys made every stored value unreadable. It is now refused (RewrapToAnotherKey, CLI code rewrap_refused). A new version of the same key, and any rewrap in derived mode, are still allowed. KeyVendorBackend::same_key decides "same key" for each vendor.

Read first: "## Summary for review" at the end of docs/plans/2026-11-05-key-vendor-backends-decisions.md.

@freshtonic
freshtonic added this pull request to stack #1523 November 6, 2026 02:11
@changeset-bot

changeset-bot Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 24478d2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
Name Type
@cipherstash/auth Minor
stash Minor
@cipherstash/stack Minor
@cipherstash/wizard Minor
@cipherstash/ffi-integration-tests Patch
@cipherstash/basic-example Patch
@cipherstash/e2e Patch
@cipherstash/bench Patch
@cipherstash/stack-drizzle Minor
@cipherstash/stack-prisma Minor
@cipherstash/stack-supabase Minor
@cipherstash/test-kit Patch
@cipherstash/prisma-example Patch
@cipherstash/auth-darwin-arm64 Minor
@cipherstash/auth-darwin-x64 Minor
@cipherstash/auth-linux-arm64-gnu Minor
@cipherstash/auth-linux-x64-gnu Minor
@cipherstash/auth-linux-x64-musl Minor
@cipherstash/auth-win32-x64-msvc Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@freshtonic freshtonic changed the title james/cip 5313 document key vendor backend trade offs capability matrix docs: key vendor backend capability matrix, and refuse an unsafe rewrap (CIP-5313) Nov 6, 2026
@coderabbitai

coderabbitai Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

@freshtonic
freshtonic force-pushed the james/cip-5312-stash-keyset-create-rewrap-commands branch from 62cbabe to bae2dfb Compare November 6, 2026 02:15
@freshtonic
freshtonic force-pushed the james/cip-5313-document-key-vendor-backend-trade-offs-capability-matrix branch from 7ebb0fd to 5a73cdc Compare November 6, 2026 02:15
@freshtonic
freshtonic force-pushed the james/cip-5312-stash-keyset-create-rewrap-commands branch from bae2dfb to 81f6647 Compare November 6, 2026 05:10
@freshtonic
freshtonic force-pushed the james/cip-5313-document-key-vendor-backend-trade-offs-capability-matrix branch from d20b25a to 8367103 Compare November 6, 2026 05:10
@freshtonic
freshtonic force-pushed the james/cip-5312-stash-keyset-create-rewrap-commands branch from 81f6647 to 12675c7 Compare November 6, 2026 05:13
@freshtonic
freshtonic force-pushed the james/cip-5313-document-key-vendor-backend-trade-offs-capability-matrix branch from 8367103 to 0605831 Compare November 6, 2026 05:13
@freshtonic
freshtonic force-pushed the james/cip-5312-stash-keyset-create-rewrap-commands branch from 12675c7 to cfa8f0d Compare November 9, 2026 04:16
@freshtonic
freshtonic force-pushed the james/cip-5313-document-key-vendor-backend-trade-offs-capability-matrix branch from 0605831 to 0c85849 Compare November 9, 2026 04:16
@freshtonic
freshtonic removed this pull request from stack #1523 November 9, 2026 04:17
@freshtonic
freshtonic added this pull request to stack #1579 November 9, 2026 04:17
Add ADR-0009 (two key modes), ADR-0010 (v2 leaf with backend and mode)
and ADR-0011 (hand-written vendor clients, signed in the guest). Widen
the Keyset term and add the key backend terms to CONTEXT.md.
Add the seams a key vendor backend needs:

- KeyLifetime and LoadedIndexKey, returned by the new provided method
  IndexKeySource::load_index_key_with_lifetime. The default is
  UntilEvicted, the ZeroKMS behaviour.
- Error::Backend { vendor, kind, source } with BackendErrorKind, and
  Error::ZeroKmsOnly { vendor, feature }.
- ZeroKmsFeature, ZeroKmsExtensions and refuse_zerokms_extensions, so a
  key vendor backend refuses a context, a decryption policy or an
  unverified context and never ignores it.
- IndexKey::from_key_bytes, a public constructor from raw key material.

The Go guest maps the two new error variants to statuses.

BREAKING CHANGE: stack_kms::Error has two new variants. An exhaustive
match on it must handle them.
…304)

The cipher loads index keys with load_index_key_with_lifetime. A key for
one settle only is never cached, a key with a TTL is evicted when the TTL
ends, and a ZeroKMS key stays until evicted. init refuses a default keyset
whose key the cipher may not keep (Error::DefaultKeysetLifetime).

A key vendor backend's NotFound now counts as keyset not found, and
Descriptor::MAX_LEN no longer reads a ZeroKMS constant.
…(CIP-5305)

Add KeyBackend (ZeroKMS or a key vendor backend), KeyVendor and KeyMode.
KeyVendor and KeyMode have stable bytes for the v2 sealed leaf; 0 is
invalid for both. DataKeySource::key_backend says which backend a source
is, and defaults to ZeroKMS.
…backend (CIP-5305)

A v2 leaf is 0x02 ‖ backend ‖ mode ‖ keyset_id ‖ iv ‖ tag_len ‖ tag ‖ ct.
The leaf AAD binds the three header bytes. A v1 leaf, its AAD and its
serde form do not change, and ZeroKMS still writes v1.

A cipher refuses a leaf that names another key backend than its own with
Error::ForeignBackend, before any key call. A key vendor backend cannot
seal yet (Error::SealUnsupported); CIP-5306 wires that path.

Add a v1 known-answer test, v2 layout pins, header-byte tamper tests,
v2 fuzz seeds, an eql-bindings pass-through test, and the Go guest
status for ForeignBackend.
The backend supports Azure Key Vault and Managed HSM. It binds the
associated data, versions the wrapped keys and supports Entra ID
credentials.
Add hand-written Key Vault fixtures, a test-only RSA key and a live test.
Run the contract suite over a Key Vault emulator for RSA and oct-HSM keys.
Check the WASI build. Stage the crate for crates.io.
…CIP-5311)

The feature is on by default. A build without it has no RSA code.
The guest routes keysets between ZeroKMS and at most one key vendor
backend (KeyRouter over GuestVendor: AWS KMS, Google Cloud KMS, Azure
Key Vault, Vault Transit or a static key). The vendor clients sign in the
guest. Their HTTP requests, the short-lived credentials they sign with and
their retry backoff all go to the host through the step loop: a step
request is now an HTTP request, a credential request (vendor and scope) or
a wait. The guest blocks on none of them and imports nothing new;
token_get stays its one import.

The Go host adds WithKeyVendor and WithKeysetRecords, a credential source
for each vendor kind with no vendor SDK dependency, and the capability
matrix in the package docs. It answers a credential request from the
source outside the client's lock, once per operation, vendor and scope,
and attaches the source's error to the call's. It sits out a wait under
the caller's context, cut to 30 seconds.

The key vendor backend keys join the guest's config frame, and the
deterministic test build reads them beside its seed.
Add WithDefaultKeyset, WithRootKeyTTL and ErrNoZeroKMS.

With WithKeyVendor and no WithCredentials, NewClient resolves no ZeroKMS
credentials. The guest routes the default keyset to the vendor
(KeyRouter::with_vendor_default) and refuses every ZeroKMS request with
the new STATUS_NO_ZEROKMS.

# Conflicts:
#	languages/golang/encrypt/client.go
#	languages/golang/encrypt/guest/src/abi.rs
#	languages/golang/encrypt/guest/src/config.rs
#	languages/golang/encrypt/transport.go
#	languages/golang/internal/guest/errors.go
#	languages/golang/internal/guest/status.go
#	packages/stack-guest-abi/src/status.rs
StaticKey had no String, GoString or LogValue, so a %+v or a slog of the
value printed the root key. Add the three methods, as AWSCredentials and
AccessToken have, and a test for each output.
Link it from stack-kms and from each vendor crate.
Point to the full matrix in stack-kms-vendor.
Tell what stash keyset rewrap does to wrapped-mode values.
Also list the vendor crates that the auth binding compiles in.
…y (CIP-5313)

A rewrap to another vendor key made the stored values unreadable.
@freshtonic
freshtonic force-pushed the james/cip-5313-document-key-vendor-backend-trade-offs-capability-matrix branch from 0c85849 to 24478d2 Compare November 10, 2026 02:37
@freshtonic
freshtonic force-pushed the james/cip-5312-stash-keyset-create-rewrap-commands branch 2 times, most recently from 18293ff to c7346e2 Compare November 12, 2026 03:44
@freshtonic
freshtonic removed this pull request from stack #1579 November 12, 2026 03:45
@freshtonic

Copy link
Copy Markdown
Contributor Author

Closed by the scope reduction. The capability matrix is now in the stack-kms-vendor crate docs (#1526) and the Go package docs (#1532). The rewrap refusal for wrapped-mode records is gone, because the wrapped data key mode is deferred. The AGENTS.md and SECURITY.md lines moved to the PRs that add the code.

The plan is docs/plans/2026-11-12-key-vendor-backends-scope-reduction.md, and the decision log (docs/plans/2026-11-05-key-vendor-backends-decisions.md, "Scope reduction") records what changed. The old branch tip is kept locally as refs/backup/2026-11-12/<branch>.

@freshtonic freshtonic closed this Nov 12, 2026
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