Title: Signing-Key Publishing, Pinning, and Rotation Policy Version: 0.1.0 Status: Phase 1 — example/demo key in repo; production KMS key pending KmsEd25519Signer (ADR-0002, skeleton today) Owner: Security Lead Last Reviewed: 2026-05-07 Next Review: 2026-08-07 Supersedes: none
The customer-facing offline verifier (genomics-verify, see
../customer/LOI_ONEPAGER.md) re-canonicalizes
a provenance manifest under JCS and verifies the detached Ed25519
signature against a public verification key that the lab fetches
out of band.
For that flow to be defensible inside a lab's QMS, three things must be unambiguous:
This file is the single source of truth for all three.
published out-of-band in-pipeline
public key ─────────────► fingerprint ──────────► pinned in pilot agreement ──► verifies
(PEM file) (sha256 hex) and shipped to lab signature
The public key file alone is not the trust anchor. The trust
anchor is the fingerprint — SHA-256(PEM-bytes) — which we
deliver to the lab through a separate, signed channel (the executed
pilot agreement, plus a confirmation email from the security lead
sent from the company's primary corporate domain).
A lab that only has the PEM file but no out-of-band fingerprint is performing TOFU (trust-on-first-use) and must not rely on the result for clinical sign-off. Ask for the pinned fingerprint.
| Channel | URL pattern | Use when |
|---|---|---|
| Repo (canonical) | https://github.com/NVIDIA-AI-Blueprints/genomics-analysis/raw/main/keys/genomics-public.pem |
Default; commit-pinned; verify the commit SHA matches the one cited in the pilot agreement. |
| Customer doc bundle | customer-bundle-<pilot_id>.zip → keys/genomics-public.pem |
When the lab took delivery of a pilot bundle; the bundle's manifest pins the fingerprint. |
| In-pipeline | The signature.json for any signed manifest carries public_key_fingerprint — the lab reconciles that against its pinned fingerprint, never against a key the same payload claims to use. |
Always, as a defense-in-depth check. |
Canonical filename: genomics-public.pem. PEM-encoded Ed25519,
SubjectPublicKeyInfo wrapper, PKCS#8 — the format
cryptography.hazmat.primitives.serialization.load_pem_public_key
parses by default.
Phase 1 note. As of v0.1.0 of this policy, the example key shipped at
../../../keys/genomics-public.pem.exampleis the only key in the repo. The example fingerprint is documented in §3 below. The production KMS-rooted key lands whenKmsEd25519Signer(ADR-0002) flips from skeleton to GA, at which point this file is updated and a new section added documenting the retirement of the example key.
| Field | Value |
|---|---|
| Key ID | example-2026-05-07 |
| Algorithm | Ed25519 |
| PEM path (in repo) | keys/genomics-public.pem.example |
| Fingerprint (SHA-256 of PEM bytes) | c45fed5f205aea057efa7314515ec3688109aa4f072aa71bd4a7fd4c48db102d |
| First used (signing) | 2026-05-07 (earliest) |
| Status | Active for demos only. Real pilot signatures must be produced by the production KMS key once KmsEd25519Signer is implemented. |
This key is example material. It is checked into the repo so the
demo script in customer/DEMO_SCRIPT.md runs end-to-end without
network access. Any signature the lab receives that verifies under
this key is by definition a demo signature, not a clinical-pilot
signature.
| Field | Value |
|---|---|
| Key ID | (assigned at provisioning time, e.g. prod-2026-Q3) |
| Algorithm | Ed25519 |
| Storage | Google Cloud KMS, asymmetric key, EC_SIGN_ED25519, HSM-backed |
| Resource path | projects/<gcp_project>/locations/<region>/keyRings/<ring>/cryptoKeys/<key>/cryptoKeyVersions/<v> |
| Public key URL | https://github.com/NVIDIA-AI-Blueprints/genomics-analysis/raw/<release_tag>/keys/genomics-public.pem |
| Fingerprint | populated at first GA release; communicated by signed email + pilot agreement appendix |
| First used | TBD (gated on KmsEd25519Signer landing) |
| Status | Pending — substrate is ready, KMS hookup is tracked in genomics/CLAUDE.md §"Substrate-hook reality" item 3. |
A lab that just received manifest.json + signature.json does this
on every signed sample, in order:
sha256(<the-PEM-bytes-as-stored-on-disk>) and confirm
it equals the pinned fingerprint. Reject otherwise.
bash
sha256sum genomics-public.pem
# expect: c45fed5f205aea057efa7314515ec3688109aa4f072aa71bd4a7fd4c48db102d (example key)public_key_fingerprint
field equal to the pinned fingerprint. Reject otherwise.
bash
jq -r .public_key_fingerprint signature.jsongenomics-verify):
bash
genomics-verify manifest.json signature.json --public-key genomics-public.pemmanifest_sha256 and the run timestamp into the lab's QMS records
alongside the run.Steps 1, 3, and 4 are non-optional. Steps 5 and 6 are the action; steps 1, 3, and 4 are what makes the action mean something.
A signing key rotates on any of:
In a confirmed-exposure rotation, step 2's overlap is omitted and the prior key is moved straight to revoked status.
Past keys we have signed under, ordered most recent first.
| Key ID | Algorithm | Fingerprint | Status | Active range | Reason for rotation |
|---|---|---|---|---|---|
example-2026-05-07 |
Ed25519 | c45fed5f205aea057efa7314515ec3688109aa4f072aa71bd4a7fd4c48db102d |
Active (demo only; not for pilots) | 2026-05-07 — present | n/a — first key in repo, example use |
Add new rows on rotation. Never delete rows; deprecation and revoke are status changes, not deletions.
../intended-use/INTENDED_USE.md — what we sign for../technical/PROVENANCE_SCHEMA.md §"Signature block" — manifest field semantics../technical/AUDIT_LOG_SPEC.md — checkpoint signatures use the same key../decisions/0002-detached-jcs-signatures.md — why JCS + detached Ed25519../customer/LOI_ONEPAGER.md §"Per-sample deliverable" — pilot-side commitment../customer/DEMO_SCRIPT.md §"Verify the manifest signature offline" — concrete walkthrough../../../compute_layer/cli/genomics_verify.py — the verifier itself../../../keys/README.md — repo-side directory README