Signed device evidence
Use this page to understand what signed device evidence can establish and why
the selected Pi 4 and QEMU images report it as unavailable.
cohesix-attestation owns the bounded wire parser, nonce state, TPM quote
checks and host certificate verifier. coh, coh-status and SwarmUI share
this vocabulary. For the operator command and pack format, see
Operator evidence.
Selected profiles and the Pi 4 decision
The stock Pi 4 has no onboard TPM. U-Boot measured boot needs a connected TPM;
enabling a build option cannot supply a missing device. The current Pi 4 is
excluded from the positive signed-device acceptance requirement. The
selected Pi manifest uses
mode = "measurement_only", required = false. It remains subject to normal
Pi boot, operator, network and trace acceptance. Secure boot and DICE are not
enabled or inferred by this exclusion. Adding a TPM module or a provisioned
DICE boot chain requires a separately declared, isolated device owner and
fresh enrollment before changing this classification.
The selected manifest schema uses explicit
disabled|measurement_only|tpm2_quote|dice_evidence modes. It also specifies
required, evidence_max_bytes, challenge_max_bytes, max_age_ms,
trust_anchor_ref, and ticket_key_policy. No automatic fallback exists.
The selected QEMU profile is disabled; the Pi profiles are measurement-only.
Both advertise that a signed-evidence provider is unavailable. The compiler
rejects required unsigned modes, missing TPM declarations, missing secure
boot/trust enrollment, literal ticket secrets in a signed profile, and signed
modes with no implemented device provider. Root independently refuses required
or signed modes before generated ticket registration. Optional profiles retain
their existing development ticket keys and report development_static.
There is currently no isolated TPM issuer, DICE CDI handoff or sealed-ticket runtime in these selected images. The host verifier does not supply those facilities. The Build Plan owns any future device-provider work; this host verifier alone does not establish production device identity.
Namespace and request lifecycle
/proc/attest/capabilities reports schema
cohesix-attestation-capabilities/v1, booleans signed_evidence and
challenge, and a bounded reason. /proc/attest/status reports
cohesix-attestation-status/v1, mode, required state, signed-evidence
availability and ticket-key classification. The selected unavailable profiles
expose only these two read-only nodes. No dummy evidence or writable challenge
is advertised.
A provider implementing this contract exposes /proc/attest/challenge and
/proc/attest/evidence through existing authenticated Secure9P operations.
The challenge is one append of at most 256 bytes, with exactly:
{"schema":"cohesix-attestation-challenge/v1","nonce":"<64 lowercase hex>","context_sha256":"<64 lowercase hex>"}
The verifier obtains the 32-byte nonce from the host OS CSPRNG and issues it once. Failure, short write, invalid response and success all consume that request. There is no retry or authority/configuration mutation. A provider must enforce per-authenticated-session correlation, one outstanding request, generated rate/byte/time bounds and one uniquely correlated response; it must never forward arbitrary TPM commands. A consumer must not enable a production provider merely because it can return this JSON.
The host reads at most 8192 encoded evidence bytes. Live timing uses monotonic elapsed time, anchored at host issue time, and rejects wall-clock rollback. The policy window is 1–60000 ms, inclusive at its configured upper limit. The TPM clock is not interpreted as Unix time.
TPM2 evidence v1
cohesix-attestation-evidence/v1 contains kind = "tpm2_quote", context,
quote, signature, and certificates. All binary fields use canonical
lowercase hex. Unknown fields, unsupported modes/algorithms, malformed lengths
and trailing TPM bytes are rejected. The quote is the exact TPMS_ATTEST
byte string, excluding the TPM2B length prefix; the signature is exact
TPMT_SIGNATURE. The supported suite is ECDSA P-256 / SHA-256. Certificates
are DER X.509, leaf AK first, at most four certificates of 2048 bytes each.
The provider never supplies a trusted root.
The context contains a proof class, 32-byte device_id and boot_id, and
eight mandatory artifact SHA-256 identities: firmware, uboot, kernel,
root_task, runtimes, resolved_manifest, image, dtb. None is a wildcard.
The context digest hashes these bytes in this exact order:
- ASCII
cohesix-attestation-context/v1followed by NUL. - One class byte: Pi device
1, QEMU virtual2, offline fixture3. - Device id, boot id, then the eight artifact digests in the order above.
TPM Quote qualifyingData is SHA-256 of ASCII
cohesix-tpm2-quote/v1, NUL, the 32 nonce bytes, then the 32 context-digest
bytes. Thus neither JSON whitespace nor object key ordering affects the
signature binding.
Verification checks the TPM-generated magic, quote type, enrolled qualified AK Name, qualifying data, safe clock, expected reset/restart epoch and clock floor. It requires exactly one SHA-256 PCR bank, a three-byte selection bitmap, strictly increasing selected PCR indices 0–23, and the SHA-256 digest of their independently expected values. All eight artifact identities must match the verifier context. Enrollment must bind that expected PCR policy to the actual measured boot chain: caller-supplied artifact names alone are not measurements.
Enrollment and trust policy
--trust-policy is an independently supplied
cohesix-attestation-trust/v1 JSON file, at most 32768 bytes. The canonical
offline fixture demonstrates its exact shape. Policy includes context, trusted
DER CA roots, a pinned AK certificate SHA-256, enrolled qualified AK Name,
PCR values, policy validity window, nonce age limit, reset/restart counters,
minimum TPM clock and a bounded certificate SHA-256 revocation list.
The verifier checks the leaf certificate against its independent pin and
validates its chain, validity and required TCG AIK EKU 2.23.133.8.3, then
verifies the quote signature. It rejects revoked roots, intermediates or leaf
certificates. CA roots are trust anchors; their permitted lifetime is bounded
by the enrollment policy. There is no network CA/CRL fetching or trust-on-first-use.
Rotate policy and AK pins through the enrollment owner, invalidate old policy
windows and publish explicit revocations. A reset or unexpected restart epoch
requires a new enrolled policy; the verifier never silently resets its floor.
Real enrollment must establish AK possession and device provenance against the expected endorsement root (including credential activation where applicable), the restricted signing-key attributes, and the measured boot/PCR mapping. A locally generated CA or a self-reported device label supplies no physical TPM provenance. Fixture trust roots may only authorize fixture class. DICE certificates are deliberately unsupported until a real device-bound CDI chain and its specific evidence profile are implemented; a generic signature is never relabelled as DICE.
Commands and retained records
coh attest --host <target> --trust-policy <enrolled-policy.json> \
--record out/attestation-record.json
coh evidence pack --host <target> --out out/incident \
--attestation-record out/attestation-record.json
coh attest --input out/incident --trust-policy <enrolled-policy.json> --json
The optional record is attached at attachments/attestation-record.json with
the existing pack inventory and digest rules. It retains the public challenge,
host issue/response times and canonical evidence envelope; the signed TPM and
DER bytes remain unchanged. Arbitrary diagnostic strings and unknown fields
cannot enter this attachment. The envelope digest is over its canonical compact
JSON serialization. Policy is supplied separately, never trusted from the pack.
Result schema cohesix-attestation-result/v1 retains verdict, reason, source
and evidence classes. Additive verified binds evidence, policy and nonce
digests plus clock/reset/restart values; proof_scope is none,
offline-signature, or live-signature. PASS means signature verification
within that explicit class and scope. Offline verification uses recorded time
and verifies a historical statement; it does not authenticate those host
timestamps or prove present device state. A fixture never becomes live evidence.
Absent providers return UNAVAILABLE; unsigned measurements and invalid
evidence fail. Only PASS exits zero. Python validates and projects this record
structurally; it never verifies or upgrades its authority.
Verification and references
Independent Python cryptography/OpenSSL fixtures exercise the exact TPM wire format and X.509 chain, with fixed offline timestamps. Tests cover nonce reuse, deadline boundaries, every artifact identity, proof-class substitution, PCR selection/value changes, reset/clock rollback, wrong/revoked/expired keys, signature corruption, truncation, trailing bytes and public-hash substitution. These fixtures are cryptographic conformance evidence, not target execution.
Normative external structures: TCG TPM Library Part 2, TCG AIK enrollment, TCG DICE architecture. Platform references: Pi 4 specifications, U-Boot measured boot.