Locksmith: verify and load proofed V1 quorum bundles #11

Open
opened 2026-07-18 21:45:47 +00:00 by caution-bot · 3 comments
caution-bot commented 2026-07-18 21:45:47 +00:00 (Migrated from codeberg.org)

Current status — 2026-09-24

Proofed V1 loading is implemented; explicit legacy import/recovery is also available.

Published PR heads checked on 2026-09-24: Platform 1f7e296, Locksmith 9f702bb, Bootproof 821b5c6. Platform's dependency/model/mock/default-runtime pins are aligned at Locksmith d2876e9; subsequent Locksmith changes concern examples, configuration, documentation and terminology. These are published implementation states, not merged/deployed-state claims.

Implemented: Historical proof verification, exact configured Keymaker PCR policy, complete V1 envelopes and typed holder associations are integrated. Separate holder-assisted ImportedV0 support preserves original recovery material and needs explicit opt-in. Raw V0 never becomes a silent fallback for malformed/failed V1; earlier incompatible V1 is not migrated.

Remaining: Complete current review/merge and the explicit unsupported/missing/wrong-typed field acceptance mapping. Attach exact deployed runtime/PCR and legacy/physical-holder evidence. Address affected parser/dependency findings where reachable; do not equate loader completion with recovery-transport hardening (#12).

Evidence: current implementation/documentation, V1 contract. The September 23 default release suite passed 11 tests; all 19 certificate-service cases passed across the initial run and socket-permission rerun. Those results apply to c33e35e, not a fresh full-suite run of the later terminology change. Earlier generation/model/loader/synthetic results remain scoped to the revisions recorded in their documentation. Current PRs remain open/unmerged.

Current Keymaker contract

The shared model defines:

  • Request: GenerateQuorumRequest::V1, with bundle_id: [u8; 16], label, threshold, max and structured keyring.
  • Response: GenerateQuorumResponse = Proofed<GenerateQuorumBundle>. The outer object is {data, necroproof}; data is tagged version: "V1" and includes bundle_id, label, keyring, required threshold/max, shardfile and public_key.
  • Holders remain Key::OpenPGP { cert } or Key::WebAuthn { credential, cert }. Multiple credentials for one holder authorize one share.
  • UUIDs use canonical 16-byte representations. No legacy keyring_hash or inline payload proof is required. V0, unproofed and earlier V1 bundles missing required quorum parameters are unsupported.
  • For Caution-backed creation, the certificate service receives organization/count, generates the bundle UUID and returns proofed public certificates; Platform verifies that evidence and retains its UUID and credential associations when calling Keymaker.

Required behavior

  • Define a single public bundle-loading API that returns the latest in-memory bundle representation.
  • Parse the current GenerateQuorumResponse proof envelope, verify its V1 data against the independently configured Keymaker PCR policy, and return the verified bundle.
  • Reject plainly legacy V0 input with an actionable unsupported-format error; no fallback/upgrade path is required in this milestone.
  • Do not hide malformed v1 data by silently treating it as v0 when it carries v1 markers or partially valid v1 structure.
  • Preserve the complete supported V1 proof envelope and holder associations; do not reinterpret or fabricate proof material for legacy input.
  • Validate current V1 fields according to the shared model: bundle_id, label, structured keyring, required threshold/max, shardfile, and public_key.
  • Treat v1 bundle_id as canonical 16-byte UUID bytes.
  • Validate max/participant count invariants at generation time in #10; at load time, reject stored v1 data that is missing required fields, has unsupported versions, has malformed key entries, or cannot provide the material needed by current consumers.
  • Preserve Key::WebAuthn { credential, cert } entries without flattening them into plain OpenPGP entries; WebAuthn/Caution-backed transport uses that association.
  • Keep v1 loading compatible with the implemented WebAuthn/Caution-backed transport path described in https://codeberg.org/caution/locksmith/issues/7 and the public certificate service behavior merged from PR #13.

Acceptance criteria

  • The V1 loader rejects raw V0 and earlier incompatible V1 fixtures clearly, without fallback or mutation. Explicit ImportedV0 acceptance belongs to the separate legacy recovery path.
  • Valid v1 bundle fixtures load directly with bundle_id: [u8; 16] and structured Vec<Key> preserved.
  • V1 fixtures cover both Key::OpenPGP { cert } and Key::WebAuthn { credential, cert } entries.
  • Malformed v1 bundles fail closed and are not misclassified as v0.
  • Unknown/unsupported future versions produce clear errors.
  • Missing or wrong-typed v1 bundle_id, label, keyring, shardfile, or public_key fields produce clear load errors.
  • Loading requires the current top-level proof envelope and quorum parameters, without legacy keyring_hash or inline proof fields.
  • Tests cover current V1 success, V0/earlier-V1 rejection, malformed-V1 failure, unsupported-version failure, missing/wrong-typed fields, and preserved WebAuthn associations.
  • Error messages identify the bundle version/shape being rejected without logging shard contents, private keys, bearer tokens, raw credentials, or decrypted secret material.
## Current status — 2026-09-24 **Proofed V1 loading is implemented; explicit legacy import/recovery is also available.** Published PR heads checked on 2026-09-24: [Platform `1f7e296`](https://codeberg.org/caution/platform/commit/1f7e2963932ac616ba6c4f0e9553112cb548ce72), [Locksmith `9f702bb`](https://codeberg.org/caution/locksmith/commit/9f702bbf465bc4968e0fa57adcbbc366a1c6977c), [Bootproof `821b5c6`](https://codeberg.org/caution/bootproof/commit/821b5c63e80f082f6d67ba3695c11416933489ec). Platform's dependency/model/mock/default-runtime pins are aligned at Locksmith `d2876e9`; subsequent Locksmith changes concern examples, configuration, documentation and terminology. These are published implementation states, not merged/deployed-state claims. **Implemented:** Historical proof verification, exact configured Keymaker PCR policy, complete V1 envelopes and typed holder associations are integrated. Separate holder-assisted ImportedV0 support preserves original recovery material and needs explicit opt-in. Raw V0 never becomes a silent fallback for malformed/failed V1; earlier incompatible V1 is not migrated. **Remaining:** Complete current review/merge and the explicit unsupported/missing/wrong-typed field acceptance mapping. Attach exact deployed runtime/PCR and legacy/physical-holder evidence. Address affected parser/dependency findings where reachable; do not equate loader completion with recovery-transport hardening (#12). Evidence: [current implementation/documentation](https://codeberg.org/caution/locksmith/src/commit/9f702bbf465bc4968e0fa57adcbbc366a1c6977c/docs/legacy-v0.md), [V1 contract](https://codeberg.org/caution/locksmith/src/commit/9f702bbf465bc4968e0fa57adcbbc366a1c6977c/docs/v1-contract.md). The September 23 default release suite passed 11 tests; all 19 certificate-service cases passed across the initial run and socket-permission rerun. Those results apply to `c33e35e`, not a fresh full-suite run of the later terminology change. Earlier generation/model/loader/synthetic results remain scoped to the revisions recorded in their documentation. Current PRs remain open/unmerged. ## Current Keymaker contract The [shared model](https://codeberg.org/caution/locksmith/src/commit/2da3be50bebd2dfdc4d0d3a94d05f55be02e910c/crates/keymaker-models/src/lib.rs) defines: - Request: `GenerateQuorumRequest::V1`, with `bundle_id: [u8; 16]`, `label`, `threshold`, `max` and structured `keyring`. - Response: `GenerateQuorumResponse = Proofed<GenerateQuorumBundle>`. The outer object is `{data, necroproof}`; `data` is tagged `version: "V1"` and includes `bundle_id`, `label`, `keyring`, required `threshold`/`max`, `shardfile` and `public_key`. - Holders remain `Key::OpenPGP { cert }` or `Key::WebAuthn { credential, cert }`. Multiple credentials for one holder authorize one share. - UUIDs use canonical 16-byte representations. No legacy `keyring_hash` or inline payload proof is required. V0, unproofed and earlier V1 bundles missing required quorum parameters are unsupported. - For Caution-backed creation, the certificate service receives organization/count, generates the bundle UUID and returns proofed public certificates; Platform verifies that evidence and retains its UUID and credential associations when calling Keymaker. ## Required behavior - Define a single public bundle-loading API that returns the latest in-memory bundle representation. - Parse the current `GenerateQuorumResponse` proof envelope, verify its V1 data against the independently configured Keymaker PCR policy, and return the verified bundle. - Reject plainly legacy V0 input with an actionable unsupported-format error; no fallback/upgrade path is required in this milestone. - Do not hide malformed v1 data by silently treating it as v0 when it carries v1 markers or partially valid v1 structure. - Preserve the complete supported V1 proof envelope and holder associations; do not reinterpret or fabricate proof material for legacy input. - Validate current V1 fields according to the shared model: `bundle_id`, `label`, structured `keyring`, required `threshold`/`max`, `shardfile`, and `public_key`. - Treat v1 `bundle_id` as canonical 16-byte UUID bytes. - Validate `max`/participant count invariants at generation time in #10; at load time, reject stored v1 data that is missing required fields, has unsupported versions, has malformed key entries, or cannot provide the material needed by current consumers. - Preserve `Key::WebAuthn { credential, cert }` entries without flattening them into plain OpenPGP entries; WebAuthn/Caution-backed transport uses that association. - Keep v1 loading compatible with the implemented WebAuthn/Caution-backed transport path described in https://codeberg.org/caution/locksmith/issues/7 and the public certificate service behavior merged from PR #13. ## Acceptance criteria - The V1 loader rejects raw V0 and earlier incompatible V1 fixtures clearly, without fallback or mutation. Explicit ImportedV0 acceptance belongs to the separate legacy recovery path. - Valid v1 bundle fixtures load directly with `bundle_id: [u8; 16]` and structured `Vec<Key>` preserved. - V1 fixtures cover both `Key::OpenPGP { cert }` and `Key::WebAuthn { credential, cert }` entries. - Malformed v1 bundles fail closed and are not misclassified as v0. - Unknown/unsupported future versions produce clear errors. - Missing or wrong-typed v1 `bundle_id`, `label`, `keyring`, `shardfile`, or `public_key` fields produce clear load errors. - Loading requires the current top-level proof envelope and quorum parameters, without legacy `keyring_hash` or inline proof fields. - Tests cover current V1 success, V0/earlier-V1 rejection, malformed-V1 failure, unsupported-version failure, missing/wrong-typed fields, and preserved WebAuthn associations. - Error messages identify the bundle version/shape being rejected without logging shard contents, private keys, bearer tokens, raw credentials, or decrypted secret material. ## Related work - Platform org-user bundle umbrella: https://codeberg.org/caution/platform/issues/384 - Keymaker v1 generation prerequisite: https://codeberg.org/caution/locksmith/issues/10 - WebAuthn signed transport proposal: https://codeberg.org/caution/locksmith/issues/7 - Public certificate service foundation merged manually from PR #13: https://codeberg.org/caution/locksmith/pulls/13
caution-bot commented 2026-07-19 20:59:21 +00:00 (Migrated from codeberg.org)

Updated this issue against current main after the public certificate service foundation from PR #13 was manually merged.

Key corrections:

  • Keymaker v1 bundle_id is now [u8; 16] canonical UUID bytes, not [u8; 32].
  • Public certificate service requests no longer accept caller-supplied bundle_id; the route generates it and returns it in the proofed bundle.
  • V1 bundle loading should preserve structured Key::WebAuthn { credential, cert } associations for future Caution-backed shard recryption.
  • V1 loading should not require v0-only keyring_hash or necroproof fields unless a future Keymaker model adds them explicitly.
Updated this issue against current `main` after the public certificate service foundation from PR #13 was manually merged. Key corrections: - Keymaker v1 `bundle_id` is now `[u8; 16]` canonical UUID bytes, not `[u8; 32]`. - Public certificate service requests no longer accept caller-supplied `bundle_id`; the route generates it and returns it in the proofed bundle. - V1 bundle loading should preserve structured `Key::WebAuthn { credential, cert }` associations for future Caution-backed shard recryption. - V1 loading should not require v0-only `keyring_hash` or `necroproof` fields unless a future Keymaker model adds them explicitly.
vkobel commented 2026-09-16 16:03:10 +00:00 (Migrated from codeberg.org)

Historical proof verification and Platform integration are implemented.

  • Certificates are verified at the authenticated generation timestamp; PCR-policy cutoffs use that timestamp.
  • Platform API/CLI and the application runtime use the corrected loader.
  • Multi-holder PGP recovery verifies holder identities, threshold and the reconstructed key.

Commits: Bootproof 821b5c6, Locksmith 07041e4 / 9322956, Platform d3b2dc0.

V0 compatibility remains deferred. Earlier V1 bundles without the required threshold/max fields are also rejected; compatibility/migration remains unresolved.

Historical proof verification and Platform integration are implemented. - Certificates are verified at the authenticated generation timestamp; PCR-policy cutoffs use that timestamp. - Platform API/CLI and the application runtime use the corrected loader. - Multi-holder PGP recovery verifies holder identities, threshold and the reconstructed key. Commits: Bootproof `821b5c6`, Locksmith `07041e4` / `9322956`, Platform `d3b2dc0`. V0 compatibility remains deferred. Earlier V1 bundles without the required `threshold`/`max` fields are also rejected; compatibility/migration remains unresolved.
vkobel commented 2026-09-17 15:03:23 +00:00 (Migrated from codeberg.org)

Current proof-wrapped V1 bundles load and support the demonstrated recovery flow. Historical proof verification, PCR-policy cutoffs and structured holder associations are implemented.

The central outstanding requirement remains V0 fallback/upgrade: the loader intentionally rejects V0. Earlier V1 bundles without threshold/max are also rejected, with no migration path.

Current model tests pass, including intentional V0 rejection and missing quorum-parameter rejection. This is not evidence of the compatibility acceptance criteria passing.

Before closure:

  • Implement the promised compatibility/migration path, or explicitly revise the supported-format policy.
  • Complete the explicit loader regression matrix for unsupported versions and missing/wrong-typed fields.
  • Update the issue’s older V1 schema description to the current proof-wrapped contract.
Current proof-wrapped V1 bundles load and support the demonstrated recovery flow. Historical proof verification, PCR-policy cutoffs and structured holder associations are implemented. The central outstanding requirement remains V0 fallback/upgrade: the loader intentionally rejects V0. Earlier V1 bundles without threshold/max are also rejected, with no migration path. Current model tests pass, including intentional V0 rejection and missing quorum-parameter rejection. This is not evidence of the compatibility acceptance criteria passing. Before closure: - Implement the promised compatibility/migration path, or explicitly revise the supported-format policy. - Complete the explicit loader regression matrix for unsupported versions and missing/wrong-typed fields. - Update the issue’s older V1 schema description to the current proof-wrapped contract.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
public/locksmith#11
No description provided.