jouleclaw-attest-vendor: read TDX and SNP fields at their published offsets #389

Merged
dcharlot merged 1 commit from fix/attest-vendor-offsets into main 2026-10-21 10:19:10 -04:00
Owner

Found while verifying sweep 2026-10-19 item #5 (attestation). It is not part of the sweep's list.

jouleclaw-attest-vendor read the wrong bytes for most of the fields it emits. Its test fixtures were built from the same constants, so nothing could catch it.

Field Was Published / sandbox-tee
TDX header 52 bytes 48 (qe_vendor_id at 12)
TDX TD 1.0 body 528 bytes 584
TDX mrtd body+0 (TEE_TCB_SVN, MRSEAM) body+136
TDX rtmr0..3 body+168/216/264/312 body+328/376/424/472
TDX report_data body+376 (that is RTMR1) body+520
TDX v5 read like v4 6-byte body descriptor first
SNP launch measurement 0x130 (inside author_key_digest) 0x090
SNP id_key_digest 0x160 (report_id_ma) 0x0E0

Unchanged: SNP report_data at 0x050 and host_data at 0x0C0 were already right.

Every offset is the one sandbox-tee's verifier uses, and agrees with the published layouts. The parser now also refuses, rather than reading them at TD offsets:

  • a quote whose tee_type is not TDX (0x81);
  • a v5 quote whose body is not a TD report (type 2, 584 bytes, or type 3, 648 bytes, with a matching size).

Tests. The fixtures are rewritten from literal published offsets, independent of the parser's constants. Every field gets its own marker, with decoys at the offsets that were read before.

Also fixed in the same functions: clippy's vec_init_then_push, and a module-doc list item clippy flagged. The doc no longer claims a tcb_svn field it never emitted.

Reach. No crate in the tree depends on this one, so the defect was latent.

Verification (build host)

  • Tests: 12. Clippy -D warnings and rustdoc -D warnings are clean.
  • Mutation testing: 13 mutants, all killed.
    • Six put back an old offset, i.e. exactly the code this replaces.
    • The other seven remove the tee-type check, the v5 descriptor and size checks, the TD 1.5 length, v5 support, or the short-body check.

🤖 Generated with Claude Code

Found while verifying sweep 2026-10-19 item #5 (attestation). It is not part of the sweep's list. `jouleclaw-attest-vendor` read the wrong bytes for most of the fields it emits. Its test fixtures were built from the same constants, so nothing could catch it. | Field | Was | Published / sandbox-tee | |---|---|---| | TDX header | 52 bytes | **48** (qe_vendor_id at 12) | | TDX TD 1.0 body | 528 bytes | **584** | | TDX mrtd | body+0 (TEE_TCB_SVN, MRSEAM) | **body+136** | | TDX rtmr0..3 | body+168/216/264/312 | **body+328/376/424/472** | | TDX report_data | body+376 (that is RTMR1) | **body+520** | | TDX v5 | read like v4 | **6-byte body descriptor first** | | SNP launch measurement | 0x130 (inside author_key_digest) | **0x090** | | SNP id_key_digest | 0x160 (report_id_ma) | **0x0E0** | Unchanged: SNP report_data at 0x050 and host_data at 0x0C0 were already right. Every offset is the one `sandbox-tee`'s verifier uses, and agrees with the published layouts. The parser now also refuses, rather than reading them at TD offsets: - a quote whose `tee_type` is not TDX (0x81); - a v5 quote whose body is not a TD report (type 2, 584 bytes, or type 3, 648 bytes, with a matching size). **Tests.** The fixtures are rewritten from literal published offsets, independent of the parser's constants. Every field gets its own marker, with decoys at the offsets that were read before. **Also fixed in the same functions:** clippy's `vec_init_then_push`, and a module-doc list item clippy flagged. The doc no longer claims a `tcb_svn` field it never emitted. **Reach.** No crate in the tree depends on this one, so the defect was latent. ## Verification (build host) - **Tests:** 12. Clippy `-D warnings` and rustdoc `-D warnings` are clean. - **Mutation testing:** 13 mutants, all killed. - Six put back an old offset, i.e. exactly the code this replaces. - The other seven remove the tee-type check, the v5 descriptor and size checks, the TD 1.5 length, v5 support, or the short-body check. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jouleclaw-attest-vendor: read TDX and SNP fields at their published offsets
All checks were successful
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m9s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 9s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 2m22s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 1m3s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 2m20s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m55s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 2m39s
50ec5d3339
The parser read the wrong bytes for most of the fields it emits. Its test
fixtures were built from the same constants, so nothing could catch it:

TDX:
- The header is 48 bytes, not 52; qe_vendor_id sits at byte 12.
- The TD 1.0 report body is 584 bytes, not 528.
- mrtd is at body+136, not body+0, which is TEE_TCB_SVN and MRSEAM.
- rtmr0..3 are at body+328/376/424/472, not 168/216/264/312.
- report_data is at body+520, not body+376, which is RTMR1.
- A v5 quote is not "backward-compatible on the header fields": a 6-byte
  body descriptor (type, size) comes before its body.

SNP:
- The launch measurement is at 0x090, not 0x130, which lies inside
  author_key_digest.
- id_key_digest is at 0x0E0, not 0x160, which is report_id_ma.
- report_data at 0x050 and host_data at 0x0C0 were already right.

Every offset is the one sandbox-tee's verifier uses, and agrees with the
published layouts.

The parser now also refuses a quote whose tee_type is not TDX (0x81), and a
v5 quote whose body is not a TD report (type 2, 584 bytes, or type 3,
648 bytes, with a matching size), rather than reading them at TD offsets.

The fixtures are rewritten from literal published offsets, independent of
the parser's constants. Every field gets its own marker, with decoys at the
offsets that were read before. The vec_init_then_push pattern and a
module-doc list item that clippy flagged are fixed in the same functions;
the doc no longer claims a tcb_svn field it never emitted.

No crate in the tree depends on this one, so the defect was latent.

Tests: 12. Mutation testing: 13 mutants, all killed. Six put back an old
offset, which is exactly the code this replaces. The other seven remove the
tee-type check, the v5 descriptor and size checks, the TD 1.5 length, v5
support, or the short-body check.

Verified on the build host: clippy -D warnings and rustdoc -D warnings
clean on jouleclaw-attest-vendor.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!389
No description provided.