Harden reusable keychain API

This commit is contained in:
Eric Wendland 2026-05-26 18:58:25 +02:00
commit b6ffcde54c
6 changed files with 410 additions and 33 deletions

View file

@ -352,13 +352,16 @@ are updated with signed `geth keychain admin-add` and `geth keychain
admin-revoke` operations; `AdminKeyAdd` carries the public key material needed
to reconstruct an OpenSSH `allowed_signers` view. `geth keychain verify` replays
the log against the previously accepted admin-key view, mirroring the `git-skm`
pattern of verifying key-registry changes from a prior trusted state. `geth
keychain sync <node>` pulls keychain operations and signatures from an imported
peer over Iroh and imports only operations with a valid OpenSSH signature from a
currently trusted admin key over the canonical payload. See
`docs/sigchain-keychain.md` for the detailed sigchain design. This is currently
a pull-based signed operation log, not a CRDT or Keyhive-style convergent
authority.
pattern of verifying key-registry changes from a prior trusted state. The
transport-neutral replay rules, application-specific signature namespaces,
allowed-signers projection, and JSONL sigchain helpers live in `geth-keychain`
so other applications can reuse the same identity-log model without depending
on the daemon, SQLite, Iroh, or local control. `geth keychain sync <node>` pulls
keychain operations and signatures from an imported peer over Iroh and imports
only operations with a valid OpenSSH signature from a currently trusted admin
key over the canonical payload. See `docs/sigchain-keychain.md` for the
detailed sigchain design. This is currently a pull-based signed operation log,
not a CRDT or Keyhive-style convergent authority.
New devices can use the node enrollment flow instead of hand-editing keychain
state. `geth node enroll request` creates a canonical, agent-key-signed request

View file

@ -332,6 +332,11 @@ resource-scoped capability decisions.
- `[x]` `geth-keychain` exposes transport-neutral allowed-signers projection,
replay verification with an injected verifier, and appendable JSONL
sigchain encode/decode helpers for static hosting or alternate transports.
- `[x]` `geth-keychain` exposes `KeychainProfile` so non-geth applications
can use distinct signature namespaces and default principals.
- `[x]` `geth-keychain` exposes a `KeychainSignatureVerifier` trait so
callers can plug in OpenSSH, HSM, WebCrypto, service-side, or test
verification backends without daemon coupling.
- `[x]` `docs/sigchain-keychain.md` documents the sigchain data model,
verification algorithm, commands, and current security limits.
- `[x]` Missing `ssh-keygen` or unavailable hardware keys produce clear

View file

@ -26,6 +26,19 @@ The durable log is `KeychainOp[]` plus `KeychainOpSignature[]`. Each operation
has a deterministic canonical signing payload under the
`geth.keychain.v1@geth.local` namespace.
The namespace is part of a `KeychainProfile`. geth uses:
- `geth.keychain.v1@geth.local`
- `geth.node-enrollment-request.v1@geth.local`
- default admin principal `admin`
Other applications should create their own profile with explicit namespaces or
`KeychainProfile::for_application("<app>", "<domain>")`. For example,
`for_application("acme-notes", "example.com")` produces
`acme-notes.keychain.v1@example.com`. This prevents signatures from one
application's keychain from being replayed into another application's
keychain.
Important operation kinds:
- `KeychainInit`
@ -105,12 +118,31 @@ provide:
- ordered or unordered `KeychainOp[]`
- `KeychainOpSignature[]`
- a signature verification callback
- a `KeychainProfile`
- a `KeychainSignatureVerifier`
The callback is responsible for the cryptographic backend, such as
`ssh-keygen -Y verify`, WebCrypto, an HSM, or a test verifier. The crate owns
the replay order, bootstrap rule, previous-view authorization rule,
`allowed_signers` projection, and reduced keychain view.
The verifier is responsible for the cryptographic backend, such as
`ssh-keygen -Y verify`, WebCrypto, an HSM, a service-side verifier, or a test
verifier. The crate owns the replay order, bootstrap rule, profile namespace
check, previous-view authorization rule, `allowed_signers` projection, and
reduced keychain view.
Minimal reusable Rust shape:
```rust
let profile = geth_keychain::KeychainProfile::for_application(
"acme-notes",
"example.com",
)?;
let entries = geth_keychain::decode_sigchain_jsonl(sigchain_text)?;
let (ops, signatures) = geth_keychain::flatten_sigchain_entries(&entries);
let report = geth_keychain::verify_sigchain_with_profile(
&ops,
&signatures,
&profile,
&my_verifier,
);
```
## Static Sigchain File