Keymaker: generate v1 quorum bundles from structured OpenPGP/WebAuthn keys #10

Closed
opened 2026-07-18 21:45:46 +00:00 by caution-bot · 5 comments
caution-bot commented 2026-07-18 21:45:46 +00:00 (Migrated from codeberg.org)

Current status — 2026-09-24

V1 generation is implemented; final review and acceptance mapping remain.

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: Structured external-PGP/passkey/mixed holders, quorum dimensions, certificate capabilities, independent holder key identities, preserved credential associations, and the complete proof-bound response are implemented. The accepted scope excludes V0 generation; explicit ImportedV0 recovery does not change this.

Remaining: Map the retained generation/negative-case criteria to current tests and complete review/merge of PR #15. Hosted access and actual network restrictions are tracked in Platform #349; termination/replacement behavior in #2. Record the exact deployed Keymaker/PCRs for integrated acceptance. These operational requirements are not missing V1 schema implementation.

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.

Motivation

Platform's organization-user quorum flow needs to assemble typed key material from:

  • existing user-provided OpenPGP certificates; and
  • Caution-backed/WebAuthn-derived OpenPGP certificates returned by the public certificate service.

The public certificate service now generates its own per-request bundle UUID, derives OpenPGP public certificates for the requested organization/count, embeds organization and bundle identity as critical Caution CA UID certification notations, and returns a Proofed<PublicCertificateBundle> containing data.bundle_id plus armored public certificates. Platform uses those returned certificates and bundle id when assembling the Keymaker v1 request.

The implementation now accepts the shared V1 request envelope and returns proofed V1 responses; the legacy V0 route is not retained. The new flow should not depend on clients submitting arbitrary service URLs, arbitrary derivation paths, or untyped JSON blobs.

Generation requirements

  • Accept top-level keymaker_models::generate_quorum::GenerateQuorumRequest::V1 at /generate_quorum; reject legacy V0 requests clearly.
  • Treat bundle_id as canonical 16-byte UUID bytes.
  • Validate threshold, max, and keyring.len() consistently; reject threshold == 0, threshold > max, and mismatched max.
  • Support structured key entries:
    • Key::OpenPGP { cert } for user-provided OpenPGP certificates;
    • Key::WebAuthn { credential, cert } for Caution-backed/WebAuthn-associated certificates.
  • For both key entry types, parse the armored OpenPGP certificate and require the key capabilities needed by Keymaker/Locksmith shard handling.
  • For Caution-backed/WebAuthn entries, preserve the WebAuthn credential association in the returned v1 bundle. Do not flatten these entries into plain OpenPGP entries.
  • For Caution-backed/WebAuthn entries, Keymaker does not load a Caution quorum, call Keyfork, or re-derive the public certificate material. The platform API/public certificate service boundary is responsible for producing and validating Caution-backed certificates before they reach Keymaker.
  • Keymaker should parse the submitted certificates, enforce the key capabilities needed for shard generation, preserve the structured WebAuthn credential association, and include that association in the returned v1 bundle. It should not require Caution service trust anchors, public-certificate necroproof verification, or Caution CA UID-certification verification in the initial v1 generation path.
  • If later designs require Keymaker to authenticate more Caution-backed certificate metadata, add that proof material explicitly to the shared v1 model rather than assuming v0 keyring_hash or inline necroproof fields exist on v1.
  • Generate and return the complete proof-wrapped V1 response with matching bundle_id, label, keyring, threshold, max, shardfile, and public_key.
  • Preserve deterministic holder ordering and reject duplicate primary/signing/encryption identities between holders. ECDH identity is curve/public point regardless of KDF hash/cipher; equivalent encryption subkeys within one holder are valid. Existing bundles sharing encryption material require separate assessment/migration; validation upgrades do not repair them.

Acceptance criteria

  • /generate_quorum accepts valid v1 requests and returns valid v1 responses.
  • Legacy V0 requests are rejected clearly; retaining a manual CLI command does not imply legacy wire compatibility.
  • V1 request validation is covered by tests for invalid thresholds, mismatched max, malformed/unsupported certs, duplicate effective keys, and mismatched bundle-context data where that context is present in certificate metadata.
  • V1 response tests prove bundle_id, label, structured keyring, threshold and max match the request, that shardfile/public_key are parseable, and that the outer proof covers the complete V1 payload.
  • OpenPGP capability checks apply to certificates inside both Key::OpenPGP and Key::WebAuthn entries.
  • Caution-backed/WebAuthn-derived certificate handling does not require Keymaker to load the Caution quorum or re-derive certificate material; Keymaker trusts the platform/public-certificate-service boundary for derivation and only enforces the certificate/keyring invariants it needs to generate shards.
  • Tests or contract fixtures cover mixed OpenPGP + WebAuthn keyrings.
  • The V1 payload does not use legacy keyring_hash or inline necroproof; the current response requires its top-level proof envelope.
## Current status — 2026-09-24 **V1 generation is implemented; final review and acceptance mapping remain.** 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:** Structured external-PGP/passkey/mixed holders, quorum dimensions, certificate capabilities, independent holder key identities, preserved credential associations, and the complete proof-bound response are implemented. The accepted scope excludes V0 generation; explicit ImportedV0 recovery does not change this. **Remaining:** Map the retained generation/negative-case criteria to current tests and complete review/merge of PR #15. Hosted access and actual network restrictions are tracked in Platform #349; termination/replacement behavior in #2. Record the exact deployed Keymaker/PCRs for integrated acceptance. These operational requirements are not missing V1 schema implementation. Evidence: [current implementation/documentation](https://codeberg.org/caution/locksmith/src/commit/9f702bbf465bc4968e0fa57adcbbc366a1c6977c/crates/keymaker/src/routes/generate_quorum.rs), [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. ## Motivation Platform's organization-user quorum flow needs to assemble typed key material from: - existing user-provided OpenPGP certificates; and - Caution-backed/WebAuthn-derived OpenPGP certificates returned by the public certificate service. The public certificate service now generates its own per-request bundle UUID, derives OpenPGP public certificates for the requested organization/count, embeds organization and bundle identity as critical Caution CA UID certification notations, and returns a `Proofed<PublicCertificateBundle>` containing `data.bundle_id` plus armored public certificates. Platform uses those returned certificates and bundle id when assembling the Keymaker v1 request. The implementation now accepts the shared V1 request envelope and returns proofed V1 responses; the legacy V0 route is not retained. The new flow should not depend on clients submitting arbitrary service URLs, arbitrary derivation paths, or untyped JSON blobs. ## Generation requirements - Accept top-level `keymaker_models::generate_quorum::GenerateQuorumRequest::V1` at `/generate_quorum`; reject legacy V0 requests clearly. - Treat `bundle_id` as canonical 16-byte UUID bytes. - Validate `threshold`, `max`, and `keyring.len()` consistently; reject `threshold == 0`, `threshold > max`, and mismatched `max`. - Support structured key entries: - `Key::OpenPGP { cert }` for user-provided OpenPGP certificates; - `Key::WebAuthn { credential, cert }` for Caution-backed/WebAuthn-associated certificates. - For both key entry types, parse the armored OpenPGP certificate and require the key capabilities needed by Keymaker/Locksmith shard handling. - For Caution-backed/WebAuthn entries, preserve the WebAuthn credential association in the returned v1 bundle. Do not flatten these entries into plain OpenPGP entries. - For Caution-backed/WebAuthn entries, Keymaker does **not** load a Caution quorum, call Keyfork, or re-derive the public certificate material. The platform API/public certificate service boundary is responsible for producing and validating Caution-backed certificates before they reach Keymaker. - Keymaker should parse the submitted certificates, enforce the key capabilities needed for shard generation, preserve the structured WebAuthn credential association, and include that association in the returned v1 bundle. It should not require Caution service trust anchors, public-certificate necroproof verification, or Caution CA UID-certification verification in the initial v1 generation path. - If later designs require Keymaker to authenticate more Caution-backed certificate metadata, add that proof material explicitly to the shared v1 model rather than assuming v0 `keyring_hash` or inline `necroproof` fields exist on v1. - Generate and return the complete proof-wrapped V1 response with matching `bundle_id`, `label`, `keyring`, `threshold`, `max`, `shardfile`, and `public_key`. - Preserve deterministic holder ordering and reject duplicate primary/signing/encryption identities between holders. ECDH identity is curve/public point regardless of KDF hash/cipher; equivalent encryption subkeys within one holder are valid. Existing bundles sharing encryption material require separate assessment/migration; validation upgrades do not repair them. ## Acceptance criteria - `/generate_quorum` accepts valid v1 requests and returns valid v1 responses. - Legacy V0 requests are rejected clearly; retaining a manual CLI command does not imply legacy wire compatibility. - V1 request validation is covered by tests for invalid thresholds, mismatched `max`, malformed/unsupported certs, duplicate effective keys, and mismatched bundle-context data where that context is present in certificate metadata. - V1 response tests prove `bundle_id`, `label`, structured `keyring`, `threshold` and `max` match the request, that `shardfile`/`public_key` are parseable, and that the outer proof covers the complete V1 payload. - OpenPGP capability checks apply to certificates inside both `Key::OpenPGP` and `Key::WebAuthn` entries. - Caution-backed/WebAuthn-derived certificate handling does not require Keymaker to load the Caution quorum or re-derive certificate material; Keymaker trusts the platform/public-certificate-service boundary for derivation and only enforces the certificate/keyring invariants it needs to generate shards. - Tests or contract fixtures cover mixed OpenPGP + WebAuthn keyrings. - The V1 payload does not use legacy `keyring_hash` or inline `necroproof`; the current response requires its top-level proof envelope. ## Related work - Platform org-user bundle umbrella: https://codeberg.org/caution/platform/issues/384 - Locksmith v1 bundle loading: https://codeberg.org/caution/locksmith/issues/11 - Public certificate service foundation merged manually from PR #13: https://codeberg.org/caution/locksmith/pulls/13 - Locksmith WebAuthn transport proposal: https://codeberg.org/caution/locksmith/issues/7
caution-bot commented 2026-07-19 21:20:47 +00:00 (Migrated from codeberg.org)

Updated this issue for the finalized public certificate service foundation on current main.

Main consistency fixes:

  • removed stale wording that implied Keymaker v1 receives organization/user UUID fields or caller-supplied derivation paths;
  • aligned bundle_id with the current [u8; 16] model;
  • clarified that the public certificate service generates the Caution-backed bundle UUID/certificates first, and platform then assembles the Keymaker v1 request;
  • kept WebAuthn association preservation and certificate verification requirements without inventing v0-only keyring_hash/necroproof fields for v1.
Updated this issue for the finalized public certificate service foundation on current `main`. Main consistency fixes: - removed stale wording that implied Keymaker v1 receives organization/user UUID fields or caller-supplied derivation paths; - aligned `bundle_id` with the current `[u8; 16]` model; - clarified that the public certificate service generates the Caution-backed bundle UUID/certificates first, and platform then assembles the Keymaker v1 request; - kept WebAuthn association preservation and certificate verification requirements without inventing v0-only `keyring_hash`/`necroproof` fields for v1.
caution-bot commented 2026-07-19 21:24:13 +00:00 (Migrated from codeberg.org)

Updated per reviewer clarification: Keymaker should not load a Caution quorum or re-derive Caution-backed public certificate material for v1 generation.

The issue now treats the platform API/public certificate service boundary as responsible for deriving/validating Caution-backed certificates before they reach Keymaker. Keymaker's initial v1 responsibility is to parse the submitted certs, enforce shard-generation key capability requirements, preserve Key::WebAuthn { credential, cert } associations, and return the structured v1 bundle without requiring public-cert-service trust anchors or necroproof verification.

Updated per reviewer clarification: Keymaker should not load a Caution quorum or re-derive Caution-backed public certificate material for v1 generation. The issue now treats the platform API/public certificate service boundary as responsible for deriving/validating Caution-backed certificates before they reach Keymaker. Keymaker's initial v1 responsibility is to parse the submitted certs, enforce shard-generation key capability requirements, preserve `Key::WebAuthn { credential, cert }` associations, and return the structured v1 bundle without requiring public-cert-service trust anchors or necroproof verification.
vkobel commented 2026-09-16 16:02:56 +00:00 (Migrated from codeberg.org)

Platform now supports PGP-only, WebAuthn-only and mixed bundle creation.

  • Verifies certificate-service proofs, Caution CA signatures and organization/bundle/index bindings before calling Keymaker.
  • Preserves holder/credential associations and verifies the requested threshold and holder count.
  • Mock tests cover creation, download, CLI encryption and rejection of invalid certificates/proofs.

Platform commits: ee9ab08, 706b2d8; quorum-parameter binding: Locksmith 0e70535, Platform f2d0ab4.

Real certificate-service bootstrap and Nitro validation remain outstanding. This does not implement WebAuthn recovery or complete legacy compatibility.

Platform now supports PGP-only, WebAuthn-only and mixed bundle creation. - Verifies certificate-service proofs, Caution CA signatures and organization/bundle/index bindings before calling Keymaker. - Preserves holder/credential associations and verifies the requested threshold and holder count. - Mock tests cover creation, download, CLI encryption and rejection of invalid certificates/proofs. Platform commits: `ee9ab08`, `706b2d8`; quorum-parameter binding: Locksmith `0e70535`, Platform `f2d0ab4`. Real certificate-service bootstrap and Nitro validation remain outstanding. This does not implement WebAuthn recovery or complete legacy compatibility.
vkobel commented 2026-09-17 15:02:53 +00:00 (Migrated from codeberg.org)

V1 generation is implemented and integrated into the demonstrated end-to-end flow: structured OpenPGP/WebAuthn/mixed inputs, quorum/certificate/duplicate-key validation, preserved credential associations and proof-bound output.

Remaining acceptance gap: the route only accepts V1; the promised legacy V0 request path is absent. Keep this issue open unless that compatibility requirement is explicitly retired.

Please also reconcile the contract wording:

  • Current V1 responses are proof-wrapped and require threshold/max.
  • Certificate-service provenance and organization/bundle context are verified upstream by Platform. Keymaker enforces generation invariants and preserves the authenticated associations; its acceptance criteria should reflect that boundary.
V1 generation is implemented and integrated into the demonstrated end-to-end flow: structured OpenPGP/WebAuthn/mixed inputs, quorum/certificate/duplicate-key validation, preserved credential associations and proof-bound output. Remaining acceptance gap: the route only accepts V1; the promised legacy V0 request path is absent. Keep this issue open unless that compatibility requirement is explicitly retired. Please also reconcile the contract wording: - Current V1 responses are proof-wrapped and require threshold/max. - Certificate-service provenance and organization/bundle context are verified upstream by Platform. Keymaker enforces generation invariants and preserves the authenticated associations; its acceptance criteria should reflect that boundary.
Owner

Fully implemented.

Fully implemented.
anton closed this issue 2026-10-21 20:35:25 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
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#10
No description provided.