inject: embedder-held CryptoKeys as typed key handles (#391) - #390
Closed
lannbot wants to merge 1 commit into
Closed
inject: embedder-held CryptoKeys as typed key handles (#391)#390lannbot wants to merge 1 commit into
lannbot wants to merge 1 commit into
Conversation
…ystore 0.1.0) The persisted-key slice (#389; closed-#97's sibling-package ruling honored): a NEW WIT package rather than an extension to polymorph:webcrypto, which tracks the WebCrypto standard and takes no extensions. signing-keystore stores a signing-key HANDLE under a guest-chosen name inside an embedder-chosen storage root; no key material crosses the interface in either direction, so a non-extractable key stays non-extractable forever — the property the alternative (export + re-import) cannot carry. Host module js/polyengine/src/keystore.ts, exported as @polymorph/webcrypto/keystore: one IndexedDB database per namespace, CryptoKey handles via structured clone (WebCrypto section-13 steps). Both edges enforce extractability: persist refuses an extractable key; load re-validates algorithm/type/usages/extractable===false and DISCARDS a failing entry (IndexedDB is origin-writable, so a stored entry is untrusted input on the way back in — wosh identity-store's validated predicate). The mint-bound algorithm record is rebuilt from the module constant, never read from storage. Ed25519 only in v1, per the #389 kind-coverage ruling. Gated by a new Playwright browser probe (Deno has no IndexedDB): persist -> real page reload -> load -> sign verified against the pre-reload public half, both extractability edges, planted-entry discards, namespace isolation, no-keystore refusal — 10/10. WIT validation covers the new package; publish dry-run clean; conformance failure sets byte-identical to baseline (the declared #351 debt). First consumer: polyvisor's G5 device store (platform-posture identity resume; its runtime/PERSISTENCE.md T-A). Additive surface: 0.3.1 on the next release commit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reworked in place per #391's ruling (the pivot commit's history records both shapes; #389 closed superseded, #97's NOT_PLANNED honored throughout).
What fell: the
polymorph:webcrypto-keystoreWIT package from the first commit. Store-a-handle is browser-specific — WebCrypto §13 structured clone is the only mechanism anywhere for persisting a live handle with its policy intact; TPM/SE/CNG mint inside the store and refuse import — so a WIT contract over that spread promises a shape whose substance varies by embedding (#128's test, failed at embedding granularity). The IndexedDB persistence library moves to the consumer (polyvisor's device store absorbs it).What ships — the one piece only this package can provide (#391):
webcryptoHost() → { imports, inject }on the polyengine host module.importsis exactlywebcryptoImports()'s record (which remains, unchanged — consumers spread it).inject.signingKey(key)wraps an Ed25519 private key as asignature.signing-keyhandle;inject.derivationKey(key)lands an HKDF/PBKDF2 secret on the base-secret resource its algorithm names (hkdf.ikm/pbkdf2.password— the derivation kind has no single key resource by design). No WIT change anywhere.Contract points held: kind validated at the wrap (Ed25519 only for signing — ECDSA/RSA bind digest/salt at mint and WebCrypto carries neither on the key, so a wrapped handle would have to invent what its getters must report); policy reported, never enforced — injected handles carry no mint record and the #86/#128 getters answer from the key's own
[[algorithm]]/[[usages]]/[[extractable]], verified in the probe both directions. One honest note: the{imports, inject}pairing is a documented contract rather than an enforced boundary — this module's resource classes are singletons and the runtime allocates reps lazily at the crossing; a brand check in every resource method would be enforcement theater for a misuse that currently cannot go wrong.Gates:
validate-witgreen (without the package);polyengine-module-check17/17; newpolyengine-inject-probe12/12 in real Chromium (sign+verify through an injected non-extractable key, truthful getters both extractability directions, public-key/ECDSA/AES rejections, minted+injected coexistence in one invocation, HKDF and PBKDF2 injects byte-identical to the platform's ownderiveBits); publish dry-run clean; conformance failure sets byte-identical to the stashed baseline (the declared #351 debt).Known gap, recorded: the table crossing itself (injected instance through
repFor/lookupin a live guest graph) is exercised first by polyvisor's integration — driving a real guest here would need an app-owned WIT world this package deliberately does not define.Version: purely additive host surface (
webcryptoHost, two exported types; the never-released./keystoreexport removed) → 0.3.1 on the next release commit;^0.3.0consumers pick it up without a manifest edit.