Add public certificate service foundation #13

Closed
caution-bot wants to merge 0 commits from feat/issue-383-public-cert-service-foundation into main
caution-bot commented 2026-07-19 01:11:02 +00:00 (Migrated from codeberg.org)

Summary

  • add a dedicated public-cert-service workspace crate and binary
  • add deterministic m/pgp'/kmkr'/<org>/<bundle>/<index> path helpers with UUID masking/order test vectors
  • add the initial Axum HTTP boundary with locked health reporting and fail-closed derivation requests until Locksmith/Keyfork recovery is wired in
  • add a dedicated Containerfile.public-cert-service that builds the new binary separately from Keymaker

Test plan

  • cargo test -p public-certificate-models
  • cargo test -p public-cert-service
  • cargo check -p public-cert-service --all-targets
  • cargo check --workspace --all-targets (currently fails in pre-existing crates/keymaker-client/examples/generate_quorum.rs because it constructs the top-level GenerateQuorumRequest enum as a struct; warnings also exist in Locksmith/Keymaker)

Refs https://codeberg.org/caution/platform/issues/383

## Summary - add a dedicated `public-cert-service` workspace crate and binary - add deterministic `m/pgp'/kmkr'/<org>/<bundle>/<index>` path helpers with UUID masking/order test vectors - add the initial Axum HTTP boundary with locked health reporting and fail-closed derivation requests until Locksmith/Keyfork recovery is wired in - add a dedicated `Containerfile.public-cert-service` that builds the new binary separately from Keymaker ## Test plan - `cargo test -p public-certificate-models` - `cargo test -p public-cert-service` - `cargo check -p public-cert-service --all-targets` - `cargo check --workspace --all-targets` *(currently fails in pre-existing `crates/keymaker-client/examples/generate_quorum.rs` because it constructs the top-level `GenerateQuorumRequest` enum as a struct; warnings also exist in Locksmith/Keymaker)* Refs https://codeberg.org/caution/platform/issues/383
caution-bot commented 2026-07-19 01:19:39 +00:00 (Migrated from codeberg.org)

Follow-up from request-boundary review:

  • certificate_count is typed as u8, so JSON values larger than 255 are rejected before handler logic runs.
  • organization_id and bundle_id are typed as [u8; 16], so UUID strings and wrong-length/non-byte arrays are rejected at deserialization; this service boundary only accepts canonical UUID bytes from the Caution API.
  • Added explicit regression tests for an oversized certificate_count, UUID string input, and oversized request bodies.
  • Added an explicit 4096-byte Axum body limit for this initial endpoint.

Verification:

  • cargo test -p public-cert-service
  • cargo check -p public-cert-service --all-targets
  • git diff --check
Follow-up from request-boundary review: - `certificate_count` is typed as `u8`, so JSON values larger than 255 are rejected before handler logic runs. - `organization_id` and `bundle_id` are typed as `[u8; 16]`, so UUID strings and wrong-length/non-byte arrays are rejected at deserialization; this service boundary only accepts canonical UUID bytes from the Caution API. - Added explicit regression tests for an oversized `certificate_count`, UUID string input, and oversized request bodies. - Added an explicit 4096-byte Axum body limit for this initial endpoint. Verification: - `cargo test -p public-cert-service` - `cargo check -p public-cert-service --all-targets` - `git diff --check`
caution-bot commented 2026-07-19 01:38:22 +00:00 (Migrated from codeberg.org)

Addressed both review comments in f8097de:

  • Switched the router import/use to explicit get/post route handlers instead of the routing::... qualifier.
  • Changed the public certificate handler to return the typed JSON response directly instead of a generic Response placeholder.
  • Replaced the 501 not implemented path with actual v1 bundle derivation: validate the request, request each derived XPrv from keyforkd using the existing deterministic org/bundle/index path, derive/armor the public OpenPGP certificates, and return the { data, necroproof } response envelope.

Verification:

  • cargo fmt -p public-cert-service
  • cargo test -p public-cert-service
  • cargo check -p public-cert-service --all-targets
  • cargo clippy -p public-cert-service --all-targets -- -D warnings
  • git diff --check
Addressed both review comments in `f8097de`: - Switched the router import/use to explicit `get`/`post` route handlers instead of the `routing::...` qualifier. - Changed the public certificate handler to return the typed JSON response directly instead of a generic `Response` placeholder. - Replaced the `501 not implemented` path with actual v1 bundle derivation: validate the request, request each derived XPrv from keyforkd using the existing deterministic org/bundle/index path, derive/armor the public OpenPGP certificates, and return the `{ data, necroproof }` response envelope. Verification: - `cargo fmt -p public-cert-service` - `cargo test -p public-cert-service` - `cargo check -p public-cert-service --all-targets` - `cargo clippy -p public-cert-service --all-targets -- -D warnings` - `git diff --check`
caution-bot commented 2026-07-19 02:14:39 +00:00 (Migrated from codeberg.org)

Addressed the latest review feedback in 7bf9034:

  • removed the service lifecycle/locked state; health now reports the always-ready service boundary
  • changed certificate_count to NonZeroU8 in the shared v1 model
  • removed transparent error wrappers and split out function-specific errors for armor/binding/hash/proof generation
  • stopped embedding org/bundle IDs in the OpenPGP UserID; the UserID now only carries the bundle-local index
  • derive the default OpenPGP CA certificate from the current quorum path and use it to certify generated certificate UserIDs with critical org/bundle notations
  • deterministically hash the PublicCertificateBundle and generate a bootproof necroproof over that hash
  • renamed the derivation entry point to derive_public_certificate() and removed spawn_blocking

Verification:

  • cargo test -p public-certificate-models
  • cargo test -p public-cert-service
  • cargo check -p public-cert-service --all-targets
  • cargo clippy -p public-cert-service --all-targets -- -D warnings
  • git diff --check
Addressed the latest review feedback in `7bf9034`: - removed the service lifecycle/locked state; health now reports the always-ready service boundary - changed `certificate_count` to `NonZeroU8` in the shared v1 model - removed transparent error wrappers and split out function-specific errors for armor/binding/hash/proof generation - stopped embedding org/bundle IDs in the OpenPGP UserID; the UserID now only carries the bundle-local index - derive the default OpenPGP CA certificate from the current quorum path and use it to certify generated certificate UserIDs with critical org/bundle notations - deterministically hash the `PublicCertificateBundle` and generate a bootproof necroproof over that hash - renamed the derivation entry point to `derive_public_certificate()` and removed `spawn_blocking` Verification: - `cargo test -p public-certificate-models` - `cargo test -p public-cert-service` - `cargo check -p public-cert-service --all-targets` - `cargo clippy -p public-cert-service --all-targets -- -D warnings` - `git diff --check`
caution-bot commented 2026-07-19 02:31:46 +00:00 (Migrated from codeberg.org)

Addressed the new follow-up review comments in 1aa30c5:

  • removed validate_certificate_count() and the associated validation error now that the shared v1 model uses NonZeroU8
  • removed the now-unreachable derivation invalid-request branch from the route error mapping
  • changed BindPublicCertificate, ArmorPublicCertificate, and HashBundle to carry their unique helper errors as explicit #[source] values and map them at the call sites

Verification:

  • cargo fmt -p public-certificate-models -p public-cert-service
  • cargo test -p public-cert-service
  • cargo check -p public-cert-service --all-targets
  • cargo clippy -p public-cert-service --all-targets -- -D warnings
  • git diff --check
  • cargo test -p public-certificate-models
Addressed the new follow-up review comments in `1aa30c5`: - removed `validate_certificate_count()` and the associated validation error now that the shared v1 model uses `NonZeroU8` - removed the now-unreachable derivation invalid-request branch from the route error mapping - changed `BindPublicCertificate`, `ArmorPublicCertificate`, and `HashBundle` to carry their unique helper errors as explicit `#[source]` values and map them at the call sites Verification: - `cargo fmt -p public-certificate-models -p public-cert-service` - `cargo test -p public-cert-service` - `cargo check -p public-cert-service --all-targets` - `cargo clippy -p public-cert-service --all-targets -- -D warnings` - `git diff --check` - `cargo test -p public-certificate-models`
ryansquared commented 2026-07-19 02:57:35 +00:00 (Migrated from codeberg.org)

Let's drop bundle_id from the models and have it be automatically generated in the route. That way, it's impossible for an attacker to control it: the only way it's exposed is the notation, which is signed by the already-present Caution quorum key.

Let's drop bundle_id from the models and have it be automatically generated in the route. That way, it's impossible for an attacker to control it: the only way it's exposed is the notation, which is signed by the already-present Caution quorum key.
ryansquared commented 2026-07-19 02:58:17 +00:00 (Migrated from codeberg.org)

Let's drop bundle_id from the models and have it be automatically generated in the route. That way, it's impossible for an attacker to control it: the only way it's exposed is the notation, which is signed by the already-present Caution quorum key.

Let's drop bundle_id from the models and have it be automatically generated in the route. That way, it's impossible for an attacker to control it: the only way it's exposed is the notation, which is signed by the already-present Caution quorum key.
caution-bot commented 2026-07-19 03:08:53 +00:00 (Migrated from codeberg.org)

Addressed the bundle-ID feedback in 0eb667e:

  • removed bundle_id from the v1 public certificate request model
  • generate a fresh v4 bundle UUID in the route before derivation
  • pass the generated bundle ID into derivation for the Keyfork path, CA UID notations, response bundle, and necroproof-covered bundle hash
  • added a regression test that client-supplied bundle_id is rejected at the typed request boundary

Verification:

  • cargo fmt -p public-certificate-models -p public-cert-service
  • cargo test -p public-certificate-models
  • cargo test -p public-cert-service
  • cargo check -p public-cert-service --all-targets
  • cargo clippy -p public-cert-service --all-targets -- -D warnings
  • git diff --check
Addressed the bundle-ID feedback in `0eb667e`: - removed `bundle_id` from the v1 public certificate request model - generate a fresh v4 bundle UUID in the route before derivation - pass the generated bundle ID into derivation for the Keyfork path, CA UID notations, response bundle, and necroproof-covered bundle hash - added a regression test that client-supplied `bundle_id` is rejected at the typed request boundary Verification: - `cargo fmt -p public-certificate-models -p public-cert-service` - `cargo test -p public-certificate-models` - `cargo test -p public-cert-service` - `cargo check -p public-cert-service --all-targets` - `cargo clippy -p public-cert-service --all-targets -- -D warnings` - `git diff --check`
anton commented 2026-07-19 20:55:17 +00:00 (Migrated from codeberg.org)

Merged manually via CLI

Merged manually via CLI

Pull request closed

Sign in to join this conversation.
No reviewers
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!13
No description provided.