Offline Verification Checklist
Before trusting an evidence bundle, you must complete every verification step in order. This checklist defines the minimum requirements for accepting a bundle as valid.
Phase 1: Bundle Integrity
First, verify the bundle package itself hasn't been modified in transit or storage.
- B1: Unpack ZIP without network access
- B2: Parse bundle_manifest.json
- B3: For each file in manifest, compute SHA-256 and compare to declared hash
- B4: Verify file sizes match declared sizes
- B5: Reject if any undeclared files present (optional, per implementation)
Phase 2: Policy Artifact Validation
Next, verify the policy artifact is authentic and properly formed.
- P1: Parse policy_artifact.json
- P2: Validate all required fields present
- P3: Canonicalize policy (excluding issuer.signature and policy_id)
- P4: Compute SHA-256 of canonical bytes
- P5: Compare computed hash to declared policy_id
- P6: Canonicalize policy (excluding issuer.signature only)
- P7: Verify Ed25519 signature using issuer.public_key
- P8: Validate key_id matches SHA-256 of public key bytes (first 16 hex chars)
Phase 3: Receipt Validation
Validate each receipt individually before checking chain integrity.
- R1: Load receipts in counter order (0001.json, 0002.json, ...)
- R2: For each receipt, validate schema (all required fields present)
- R3: Canonicalize receipt (excluding signer.signature and receipt_id)
- R4: Compute SHA-256, compare to declared receipt_id
- R5: Canonicalize receipt (excluding signer.signature and this_receipt_hash)
- R6: Compute SHA-256, compare to declared this_receipt_hash
- R7: Verify Ed25519 signature using signer.public_key
Phase 4: Chain Continuity
Verify the receipt chain forms an unbroken, tamper-evident sequence.
- C1: First receipt prev_receipt_hash must equal 64 zeros
- C2: Each subsequent receipt prev_receipt_hash must equal previous receipt's this_receipt_hash
- C3: Counter values must be monotonically increasing (1, 2, 3, ...)
- C4: No counter gaps allowed
- C5: All receipts reference same run_id
- C6: Parse chain_head.json
- C7: Verify head_receipt_hash matches last receipt's this_receipt_hash
- C8: Verify receipt_count matches actual count
Phase 5: Policy Consistency
Verify all receipts reference the same policy and required events are present.
- PC1: All receipts policy.policy_id must match policy artifact policy_id
- PC2: Required event types present (POLICY_LOADED, ENFORCED, etc.)
- PC3: If DRIFT_DETECTED, corresponding ENFORCED receipt must follow
- PC4: Enforcement action matches policy enforcement_mapping
Phase 6: Emit Verdict
Generate the final verdict based on all checks.
- V1: If all checks pass → verdict: PASS
- V2: If optional features degraded but core passes → verdict: PASS_WITH_CAVEATS
- V3: If any required check fails → verdict: FAIL with error_code
- V4: Include report_hash in output
- V5: Report must be deterministic (same bundle → same report)