varve is deciding, for its v1.0 trust-root ceremony, whether to keep a file-based ed25519 root or move to keyless signing over wsc. This is the consolidated version of what that would require, replacing the scattered asks in #256–#260.
First: credit where it is due. #257 is closed and 0.11.0 changed the picture materially. I re-read the source today rather than trusting my earlier notes, and src/airgapped/verifier.rs is no longer the stub it was in 0.10.0 — 1241 lines performing certificate-chain validation to a bundle Fulcio root, leaf validity at Rekor's integrated_time with codeSigning EKU, mandatory Rekor SET verification, ECDSA P-256 over the digest via the SEC1 point in the SPKI BIT STRING, revocation and identity checks — and the Rekor body binding (#135 UCA-2) verified offline. The # Not verified offline doc block is exactly the right way to ship this: it names the Merkle inclusion gap and the SCT gap and explains why each is skipped rather than leaving a reader to discover it. A previous decision on our side (DD-026) partly rested on that verifier being a stub. That premise is now wrong and we are correcting it.
Why varve cares about the answer
varve distributes signed toolchain layers. Its current root is a long-lived ed25519 key that lives in CI and signs every deposit. We just documented (varve#110) that this key exists only as a write-only GitHub Actions secret: it cannot be backed up, cannot be moved to another repository, and cannot be recovered if lost — and varve has no rotation and no revocation, so losing it ends the realm.
Keyless is attractive to us for exactly one reason, and it is worth being precise about it: it takes the long-lived secret out of CI. We are not under the illusion that it removes long-lived keys. Your own doc comment is explicit:
The bundle is signed with a long-lived offline key. Devices verify the signature against a pre-provisioned public key before using.
That is fine. A bundle-signing key is used rarely, changes rarely, and can be held under a real ceremony — offline, split custody, paper backup, annual read test. A per-deposit CI key cannot. The question is not "keys or no keys", it is which key has to be online.
What we would need
1. Signing over an arbitrary 32-byte digest (#256) — the blocker
varve signs DSSE-wrapped layer manifests, which are JSON, not WASM modules. The verify side already looks digest-shaped (verify_signature(&self, signature: &KeylessSignature, module_hash: &[u8; 32], …)), which is encouraging. What we need is the signing half to accept a caller-supplied digest with no assumption that the bytes behind it are a component.
If the parameter genuinely is just "a 32-byte hash", renaming it away from module_hash in the public API would help — the name currently implies a constraint that may not exist, and we would rather not guess.
2. A cosign-bundle adapter (#260)
Every PulseEngine repo publishes a cosign-signed SHA256SUMS.txt, and varve already ingests releases on that basis. Being able to turn an existing cosign bundle into a KeylessSignature would let us verify what we already ingest through one code path instead of two.
3. The trust bundle's own distribution story
This is the part we most want your opinion on rather than a feature. If consumers must pin a bundle-verification key, then that key is the ceremony subject, and its rotation story is the one that matters. Specifically:
- Is there an intended path for rotating the bundle-signing key, or for a new bundle to be verified against the old one?
- Is
SignedTrustBundle expected to be distributed in-band with artifacts, or provisioned out-of-band per device?
src/airgapped/tuf.rs fetches trusted_root.json over HTTPS from a raw.githubusercontent URL and parses it. That is a fetch, not TUF — there is no root.json signature chain, no threshold, no snapshot/timestamp metadata verification. Is TUF metadata verification intended to land, or is the signed bundle deliberately the trust anchor instead? Either answer is workable; we just need to know which, because our documentation has to describe it honestly to people making custody decisions.
4. #258 — the air-gapped e2e test that cannot fail
Still open, and worth prioritising above the features above. A test that never calls verify_signature reports green whatever the verifier does, and the verifier is now substantial enough that a vacuous test around it is actively misleading. We hit this class often enough in our own repo to have a name for it; we would trust the 0.11.0 verifier considerably more with a negative control proving that test goes red.
5. #259 — one Rekor log embedded, two live
Relevant to us because a signature from the non-embedded log would fail to verify offline for reasons that look nothing like the actual cause.
Hardware, since it is adjacent
We noticed HardwareSigner with tpm2 / sgx / trustzone / secure_element backends, and that sigil ships a wsc-linux-x86_64-tpm2 binary. If the v1.0 answer turns out to be "a long-lived bundle key held properly" rather than "no long-lived key", a hardware-backed signer is the natural home for it.
There is no PKCS#11 backend, which is the usual route to a YubiKey. Is that a deliberate scope decision, or simply unbuilt? Not asking for it yet — asking whether to plan around it existing.
What we are not asking for
We are not asking wsc to solve varve's custody problem. We are asking for enough surface and enough honesty about the trust model to let us decide where our long-lived key should live, and to describe that decision truthfully to people who will pin it for years. The # Not verified offline block in verifier.rs is precisely the standard we are hoping to hold ourselves to.
Happy to take any of this as a PR rather than a request if it helps — say which.
varve is deciding, for its v1.0 trust-root ceremony, whether to keep a file-based ed25519 root or move to keyless signing over
wsc. This is the consolidated version of what that would require, replacing the scattered asks in #256–#260.First: credit where it is due. #257 is closed and 0.11.0 changed the picture materially. I re-read the source today rather than trusting my earlier notes, and
src/airgapped/verifier.rsis no longer the stub it was in 0.10.0 — 1241 lines performing certificate-chain validation to a bundle Fulcio root, leaf validity at Rekor'sintegrated_timewith codeSigning EKU, mandatory Rekor SET verification, ECDSA P-256 over the digest via the SEC1 point in the SPKI BIT STRING, revocation and identity checks — and the Rekor body binding (#135 UCA-2) verified offline. The# Not verified offlinedoc block is exactly the right way to ship this: it names the Merkle inclusion gap and the SCT gap and explains why each is skipped rather than leaving a reader to discover it. A previous decision on our side (DD-026) partly rested on that verifier being a stub. That premise is now wrong and we are correcting it.Why varve cares about the answer
varve distributes signed toolchain layers. Its current root is a long-lived ed25519 key that lives in CI and signs every deposit. We just documented (varve#110) that this key exists only as a write-only GitHub Actions secret: it cannot be backed up, cannot be moved to another repository, and cannot be recovered if lost — and varve has no rotation and no revocation, so losing it ends the realm.
Keyless is attractive to us for exactly one reason, and it is worth being precise about it: it takes the long-lived secret out of CI. We are not under the illusion that it removes long-lived keys. Your own doc comment is explicit:
That is fine. A bundle-signing key is used rarely, changes rarely, and can be held under a real ceremony — offline, split custody, paper backup, annual read test. A per-deposit CI key cannot. The question is not "keys or no keys", it is which key has to be online.
What we would need
1. Signing over an arbitrary 32-byte digest (#256) — the blocker
varve signs DSSE-wrapped layer manifests, which are JSON, not WASM modules. The verify side already looks digest-shaped (
verify_signature(&self, signature: &KeylessSignature, module_hash: &[u8; 32], …)), which is encouraging. What we need is the signing half to accept a caller-supplied digest with no assumption that the bytes behind it are a component.If the parameter genuinely is just "a 32-byte hash", renaming it away from
module_hashin the public API would help — the name currently implies a constraint that may not exist, and we would rather not guess.2. A cosign-bundle adapter (#260)
Every PulseEngine repo publishes a cosign-signed
SHA256SUMS.txt, and varve already ingests releases on that basis. Being able to turn an existing cosign bundle into aKeylessSignaturewould let us verify what we already ingest through one code path instead of two.3. The trust bundle's own distribution story
This is the part we most want your opinion on rather than a feature. If consumers must pin a bundle-verification key, then that key is the ceremony subject, and its rotation story is the one that matters. Specifically:
SignedTrustBundleexpected to be distributed in-band with artifacts, or provisioned out-of-band per device?src/airgapped/tuf.rsfetchestrusted_root.jsonover HTTPS from a raw.githubusercontent URL and parses it. That is a fetch, not TUF — there is no root.json signature chain, no threshold, no snapshot/timestamp metadata verification. Is TUF metadata verification intended to land, or is the signed bundle deliberately the trust anchor instead? Either answer is workable; we just need to know which, because our documentation has to describe it honestly to people making custody decisions.4. #258 — the air-gapped e2e test that cannot fail
Still open, and worth prioritising above the features above. A test that never calls
verify_signaturereports green whatever the verifier does, and the verifier is now substantial enough that a vacuous test around it is actively misleading. We hit this class often enough in our own repo to have a name for it; we would trust the 0.11.0 verifier considerably more with a negative control proving that test goes red.5. #259 — one Rekor log embedded, two live
Relevant to us because a signature from the non-embedded log would fail to verify offline for reasons that look nothing like the actual cause.
Hardware, since it is adjacent
We noticed
HardwareSignerwith tpm2 / sgx / trustzone / secure_element backends, and that sigil ships awsc-linux-x86_64-tpm2binary. If the v1.0 answer turns out to be "a long-lived bundle key held properly" rather than "no long-lived key", a hardware-backed signer is the natural home for it.There is no PKCS#11 backend, which is the usual route to a YubiKey. Is that a deliberate scope decision, or simply unbuilt? Not asking for it yet — asking whether to plan around it existing.
What we are not asking for
We are not asking wsc to solve varve's custody problem. We are asking for enough surface and enough honesty about the trust model to let us decide where our long-lived key should live, and to describe that decision truthfully to people who will pin it for years. The
# Not verified offlineblock inverifier.rsis precisely the standard we are hoping to hold ourselves to.Happy to take any of this as a PR rather than a request if it helps — say which.