docs(seal): PIV hardware-signer plan — the final CROSS-3 pass#8
Conversation
Execution-ready plan to swap the seal's software Ed25519 signer for a YubiKey-PIV (ECDSA-P256) signer with attestation-chain verification, and to bind max_authorized to the same hardware root. Lives next to core/seal. No code change — it needs the physical token. Covers: the slot/algorithm decisions (9c, ECCP256, raw->DER, touch/PIN), the new modules (piv.py / attestation.py / pins.py + verify_seal gates G1a/G1b), D6-D7 sequencing with the hardware-gated steps marked, the hw-free vs hw-gated test split (software-EC + a checked-in attestation fixture so CI runs tokenless), threat-model deltas (closes T6 structurally), the rotation runbook, and acceptance criteria.
Reviewer's GuideAdds a new documentation file that provides a detailed, execution-ready plan for replacing the CROSS-3 seal’s software Ed25519 signer with a YubiKey-based PIV ECDSA-P256 hardware signer, including attestation-chain validation, ceiling-policy binding, sequencing, testing strategy, and operational runbook, without changing existing code or wire formats. Sequence diagram for verify_seal with PIV ECDSA-P256 pathsequenceDiagram
participant Caller
participant verify_seal
participant AttestationModule
participant PivVerifier
participant Pins
Caller->>verify_seal: verify_seal(seal)
alt signature.alg == piv-ecdsa-p256
verify_seal->>Pins: access pinned_root_ca_fingerprint
verify_seal->>Pins: access serial_allowlist
verify_seal->>AttestationModule: [G1a attestation chain check]
AttestationModule-->>verify_seal: [attestation ok / fail]
verify_seal->>Pins: access pinned_key_id
verify_seal->>PivVerifier: [G1b key_id match]
PivVerifier-->>verify_seal: [match / mismatch]
verify_seal->>PivVerifier: [G2 signature verify]
PivVerifier-->>verify_seal: [valid / invalid]
else signature.alg == ed25519
verify_seal->>Verifier: [existing Ed25519 path]
Verifier-->>verify_seal: [valid / invalid]
end
verify_seal-->>Caller: verification_result
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The plan mentions seals "carrying an attestation chain" while also stating there is no seal format change; it would help to clarify explicitly where the attestation chain is transported (e.g., only via
/api/seal/pubkeyvs embedded in the seal) and align the acceptance criteria wording with that. - For the PIV-signed ceiling policy
{max_authorized, not_after_utc, key_id, signature}, please specify the exact serialization format (e.g., JSON with canonicalization rules vs CBOR) and how canonical bytes are produced so that implementations don’t diverge. - The CA-only vs CA+serial pinning posture is described conceptually, but it would be useful to call out the concrete configuration surface (env vars / constants) that controls this choice so operators know precisely how to switch between the two modes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The plan mentions seals "carrying an attestation chain" while also stating there is no seal format change; it would help to clarify explicitly where the attestation chain is transported (e.g., only via `/api/seal/pubkey` vs embedded in the seal) and align the acceptance criteria wording with that.
- For the PIV-signed ceiling policy `{max_authorized, not_after_utc, key_id, signature}`, please specify the exact serialization format (e.g., JSON with canonicalization rules vs CBOR) and how canonical bytes are produced so that implementations don’t diverge.
- The CA-only vs CA+serial pinning posture is described conceptually, but it would be useful to call out the concrete configuration surface (env vars / constants) that controls this choice so operators know precisely how to switch between the two modes.
## Individual Comments
### Comment 1
<location path="docs/PIV_HARDWARE_SIGNER_PLAN.md" line_range="162" />
<code_context>
+
+---
+
+## 10. Acceptance criteria (done = )
+
+- `AEGIS_SEAL_BACKEND=piv` produces seals whose `signature.alg == "piv-ecdsa-p256"`, carrying an
</code_context>
<issue_to_address>
**issue (typo):** The phrase "(done = )" appears incomplete in the section header.
If this is meant to encode something specific (e.g., a status like `done = true`), please spell it out so readers understand the intended meaning of this notation.
```suggestion
## 10. Acceptance criteria (done = all criteria below are satisfied)
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
|
||
| --- | ||
|
|
||
| ## 10. Acceptance criteria (done = ) |
There was a problem hiding this comment.
issue (typo): The phrase "(done = )" appears incomplete in the section header.
If this is meant to encode something specific (e.g., a status like done = true), please spell it out so readers understand the intended meaning of this notation.
| ## 10. Acceptance criteria (done = ) | |
| ## 10. Acceptance criteria (done = all criteria below are satisfied) |
…authority gate, ceiling, CROSS-3 seal (#9) Squashed release of the 8-PR stack (#2..#8): the offline, hardware-rootable bounded-autonomy receipt and everything under it. AUTO disabled by default; the only un-built piece is the hardware-PIV signer (docs/PIV_HARDWARE_SIGNER_PLAN.md) — software Ed25519 runs the whole demo. - core/llm: single shared LLM egress + adapter (local-first fallback chain, retry/cooldown, 4-event hook bus; raw httpx, no anthropic SDK; air-gap fail-closed). [#2] - evidence: model-identity wedge — change.model_identity sealed into the bundle hash; honest UNKNOWN / unattested states, never a faked attribution. [#3] - core/risk: deterministic AUTO/HITL/HOTL/BLOCK authority model (severity != authority; AS/RD/RT -> BLOCK; spine/underlay -> >= HOTL) + the no-self-escalation ceiling. [#4] - core/promote: gate rule G5 enforces the ceiling from the sealed required tier; change.authority sealed (bundle_version 1.1->1.2). [#5] - core/seal: CROSS-3 detached, offline-verifiable bounded-autonomy receipt (Ed25519; gates G0..G6; refuses to seal an unbounded change). [#6] - serve: /api/preflight/run emits the seal; GET /api/seal/pubkey + POST /api/seal/verify; examiner PDF shows the seal. [#7] - docs: PIV hardware-signer plan — the final, hardware-gated CROSS-3 pass. [#8] Property-tested safety invariants: no-self-escalation 0-violations, every-seal-is-bounded, tamper detection, offline-keyless verify, air-gap fail-closed.
|
Superseded by the squashed release #9, now merged to main. This PR's changes are in main; closing for tidiness (branch kept for history). |
The PIV hardware-signer plan (docs-only, stacked on the seal-serve PR)
The execution-ready plan for the one remaining piece: swapping the CROSS-3 seal's software Ed25519 signer for a YubiKey-PIV (ECDSA-P256) signer with attestation-chain verification, and binding
max_authorizedto the same hardware root. No code — it needs the physical token to provision/sign/verify against; everything it plugs into (theSigner/Verifierprotocol, the G0–G6 verifier, the/api/seal/*endpoints) already ships and is property-tested.docs/PIV_HARDWARE_SIGNER_PLAN.mdcovers:r‖s→ DER gotcha, touch/PIN posture, CA+serial pinning.piv.py(PivSigner/PivVerifier),attestation.py(chain → pinned Yubico Root CA),pins.py(compiled-in fingerprint + key, not file-loaded), andverify_sealgates G1a/G1b layered before G2 (Ed25519 path unchanged).load_max_authorized()verifies a PIV-signed ceiling policy so it can't be raised by editing env (the#5-ceilingfollow-up).C_Signexercised once behind@needs_yubikey.This closes out the AEGIS upgrade arc: the plan is ready to execute the moment a YubiKey is in hand.
Summary by Sourcery
Documentation: