Hi Veraison maintainers — first, thanks for the project; the Docker deployment and the cocli/evcli/pocli tooling made a full provision-and-appraise loop straightforward to stand up.
While exercising the tpm-enacttrust scheme end-to-end (provision a CoRIM with a trust anchor + reference value, then submit a TPM quote through the challenge-response API), I noticed that the scheme appraises the signature and the PCR digest versus the reference value, but does not compare the nonce the attester bound into the quote's qualifying data (TPMS_ATTEST.ExtraData) against the session's expected nonce.
Concretely, in scheme/tpm-enacttrust/scheme.go, ExtractClaims surfaces pcr-selection, hash-algorithm, firmware-version, node-id, and pcr-digest, but not the quote's ExtraData; and AppraiseClaims checks only pcr-digest against the endorsed reference. The eat_nonce that appears in the EAR is the framework reflecting the session nonce, not evidence that the scheme verified freshness.
Impact. A correctly-signed quote over a matching PCR state, captured once, can be replayed to obtain ear.status = affirming for that instance at any later time, regardless of the instance's current state. For use cases that read affirming as evidence of present state, this is a freshness gap.
Suggested fix (happy to send a PR). Two small, separable pieces:
- In
ExtractClaims, surface the attester-bound nonce as a claim:
claims["nonce"] = []byte(decoded.AttestationData.ExtraData)
- An appraisal policy (OPA/Rego) that compares that claim against the session's expected nonce (available to the policy via the session context) and returns a contraindicated verdict on mismatch.
I'd be glad to open a PR with the one-line scheme change and a policy example, and to add a tpm-enacttrust test vector for the replay case. Is enforcing freshness in-scheme (vs. leaving it to a policy) the direction you'd prefer? Happy to follow your steer.
Thanks!
— Anton Sokolov (Tyche Institute)
Hi Veraison maintainers — first, thanks for the project; the Docker deployment and the
cocli/evcli/poclitooling made a full provision-and-appraise loop straightforward to stand up.While exercising the
tpm-enacttrustscheme end-to-end (provision a CoRIM with a trust anchor + reference value, then submit a TPM quote through the challenge-response API), I noticed that the scheme appraises the signature and the PCR digest versus the reference value, but does not compare the nonce the attester bound into the quote's qualifying data (TPMS_ATTEST.ExtraData) against the session's expected nonce.Concretely, in
scheme/tpm-enacttrust/scheme.go,ExtractClaimssurfacespcr-selection,hash-algorithm,firmware-version,node-id, andpcr-digest, but not the quote'sExtraData; andAppraiseClaimschecks onlypcr-digestagainst the endorsed reference. Theeat_noncethat appears in the EAR is the framework reflecting the session nonce, not evidence that the scheme verified freshness.Impact. A correctly-signed quote over a matching PCR state, captured once, can be replayed to obtain
ear.status = affirmingfor that instance at any later time, regardless of the instance's current state. For use cases that readaffirmingas evidence of present state, this is a freshness gap.Suggested fix (happy to send a PR). Two small, separable pieces:
ExtractClaims, surface the attester-bound nonce as a claim:I'd be glad to open a PR with the one-line scheme change and a policy example, and to add a
tpm-enacttrusttest vector for the replay case. Is enforcing freshness in-scheme (vs. leaving it to a policy) the direction you'd prefer? Happy to follow your steer.Thanks!
— Anton Sokolov (Tyche Institute)