@@ -4,117 +4,85 @@ Receipts are only as trustworthy as the signing keys behind them.
44
55This repo intentionally ** does not** ship any private signing material. Private keys must never be committed to a public repository.
66
7- ## Local evaluation
7+ ---
88
9- Generate a local dev keypair and local example receipts:
9+ ## Local evaluation (no secrets committed)
10+
11+ Generate a local dev keypair and example receipts (all ** gitignored** ):
1012
1113``` bash
1214bash scripts/gen_demo_assets.sh
13- ```
1415
15- That creates gitignored local artifacts such as :
16+ This creates:
1617
17- - ` keys/dev/dev-key-001.seed ` — private ed25519 seed
18- - ` keys/dev/dev-key-001.pub ` — public key
19- - ` examples/receipts/*.json ` — generated example receipts
18+ keys/dev/dev-key-001.seed — private ed25519 seed (0600, gitignored)
2019
21- Verify the generated receipts strictly:
20+ keys/dev/dev-key-001.pub — public key (gitignored)
2221
23- ``` bash
24- go run ./cmd/ix-an verify-dir --strict-approvals examples/receipts
25- ```
22+ examples/receipts/* .json — generated receipts (gitignored)
2623
27- ## Manual local flow
24+ Then verify strictly:
2825
29- Generate a local keypair:
26+ go run ./cmd/ix-an verify-dir examples/receipts --strict-approvals
3027
31- ``` bash
28+ If you prefer manual steps:
3229go run ./cmd/ix-an keygen --out-seed keys/dev/dev-key-001.seed --out-pub keys/dev/dev-key-001.pub
33- ```
30+ go run ./cmd/ix-an simulate --path docs/demo.txt --out /tmp/allow.json --key keys/dev/dev-key-001.seed --key-id dev-key-001
31+ go run ./cmd/ix-an verify /tmp/allow.json --strict-hashes --strict-signature
3432
35- Create a signed receipt with that key:
33+ Production guidance (baseline posture)
34+ 1) Store signing keys in KMS/HSM
3635
37- ``` bash
38- go run ./cmd/ix-an simulate \
39- --path docs/demo.txt \
40- --out /tmp/allow.receipt.json \
41- --key keys/dev/dev-key-001.seed \
42- --key-id dev-key-001
43- ```
36+ Keep private key material hardware-backed when possible (HSM / KMS / Vault with HSM-backed keys).
4437
45- Verify it with the matching public key:
38+ Limit permissions to “sign receipt” operations only.
4639
47- ``` bash
48- go run ./cmd/ix-an verify \
49- --strict-hashes \
50- --strict-signature \
51- --pubkey keys/dev/dev-key-001.pub \
52- /tmp/allow.receipt.json
53- ```
40+ Gate signing behind IAM authorization and change control in high-risk environments.
5441
55- Using ` --pubkey ` is the most explicit and deterministic way to verify a receipt during evaluation.
42+ 2) Publish a trusted public-key allowlist
5643
57- ## Baseline production posture
44+ Verification should only accept signatures from:
5845
59- ### 1) Store private keys in KMS or HSM
46+ a curated set of trusted public keys,
6047
61- Private key material should be hardware-backed or at least controlled by a hardened signing service.
48+ mapped to known key_id values,
6249
63- Minimum posture:
50+ with an explicit revocation story (even if “manual list update” in v0).
6451
65- - no raw private keys in public repos
66- - no broad filesystem access to signing keys
67- - sign-only permission boundary where possible
68- - IAM and change control around key usage
52+ 3) Rotate keys without breaking verification
6953
70- ### 2) Publish a trusted public-key allowlist
54+ Receipts include:
7155
72- Verification should only accept signatures from a curated set of trusted public keys mapped to known ` key_id ` values.
56+ integrity.signature.key_id
7357
74- At minimum, production needs:
75-
76- - an explicit list of trusted public keys
77- - stable ` key_id ` naming
78- - a process for updating trust when keys rotate or are revoked
79-
80- ### 3) Rotate keys without breaking old verification
58+ Recommended pattern:
8159
82- Receipts carry:
60+ treat key_id as immutable for a specific key version (e.g., notary-prod-2026-03)
8361
84- - ` integrity.signature. key_id`
62+ rotate by issuing a new key and a new key_id
8563
86- Recommended pattern:
64+ keep historical public keys available so old receipts remain verifiable
8765
88- - treat ` key_id ` as a specific key version, not a floating alias
89- - rotate by minting a new key and a new ` key_id `
90- - keep historical public keys available so older receipts remain verifiable
66+ 4) Separate domains (optional, but stronger)
9167
92- ### 4) Separate trust domains where appropriate
68+ For higher assurance:
9369
94- Higher-assurance deployments may want:
70+ use a distinct key for the notary’s receipt signing
9571
96- - one trust domain for receipt signing
97- - another trust domain for approval signing
98- - separate operational ownership for each
72+ and separate keys for human/ticket approvals (different trust domain)
9973
100- That reduces the blast radius of a single compromise.
74+ Threats this mitigates
10175
102- ## What good key hygiene protects against
76+ Receipt tampering (signature fails)
10377
104- Good key handling helps defend against:
78+ Receipt fabrication (unknown key_id / untrusted public key)
10579
106- - receipt tampering
107- - fabricated receipts
108- - unverifiable “audit theater”
109- - silent evidence drift
110- - accidental trust in unknown signing identities
80+ “audit theater” placeholders (strict verifier rejects)
11181
112- ## Practical rule
82+ Silent evidence drift (hash + signature binds the canonical receipt payload)
11383
114- If a buyer cannot answer ** which keys are trusted, where they live, how they rotate, and how old receipts stay verifiable ** , the evaluation is not production-credible yet.
84+ See also:
11585
116- ## Related documents
86+ docs/THREAT_MODEL.md
11787
118- - ` docs/THREAT_MODEL.md `
119- - ` docs/POLICY_INTEGRITY.md `
120- - ` docs/APPROVALS.md `
88+ docs/POLICY_INTEGRITY.md
0 commit comments