如何逐項解讀 Intel TDX Quote 的各個欄位
Read an Intel TDX Quote, Field by Field
VoltageGPU 以 voltage-verify 0.2.2 驗證一份 Intel TDX v4 quote,並逐項解析其欄位能支持的判斷及限制。該 quote 通過 15 項檢查;線上檢查中,Intel 將平台、QE 與 TDX_03 評為 UpToDate。文章指出,quote 不能證明啟動的軟件可信,也不能確保挑戰值對讀者具新鮮性;四份公開 bundle 的 RTMR2 各不相同。
Originally published on voltagegpu.com, where the bundle and every raw file are linked.
Key takeaways
- Every value below comes from one public quote, checked with voltage-verify 0.2.2.
- Six things matter to a tenant: MRTD, RTMR0 to RTMR3, REPORTDATA, the TD attributes, the TCB status and the certificate chain.
- Each proves something narrow. None shows that the VM runs software you trust.
voltage-verify reduces a TDX quote to one line: RESULT: VERIFIED. Here we open one: a quote captured on 17 September 2026 in a VoltageGPU Confidential VM with one NVIDIA RTX PRO 6000 Blackwell Server Edition. We check it, then read each field for what it proves and what it does not. The bundle is public; all outputs date from 22 October 2026.
What a TDX quote is, and who signs it
Intel TDX runs a VM as a trust domain (TD). A CPU-attested software module, the TDX module, sits between the host and the guest. It gives the guest a TD report: the TD's measurements, the platform's security versions and 64 bytes chosen by the guest, called REPORTDATA. A MAC protects the report, and only the local platform can check it.
So a Quoting Enclave, an Intel SGX enclave on the same host, checks the report and turns it into a quote anyone can verify. A version 4 quote has three parts:
- a 48-byte header: version 4, key type 2 (ECDSA P-256), TEE type 0x81 (TDX);
- the 584-byte TD report;
- the signature data: quote signature, attestation key, the Quoting Enclave's report and the platform's certificate chain.
The attestation key signs the header and the TD report. The Quoting Enclave's report vouches for that key: its data starts with a SHA-256 of the key and the enclave's authentication data. The platform's PCK key signs that report. Intel issues the PCK certificate, whose chain ends at the Intel SGX Root CA. VoltageGPU appears nowhere in this chain.
Step 1: verify the bundle
The bundle holds the quote, a manifest, NVIDIA's GPU tokens and Intel's documents from the day of capture (README). The commands are written for Linux and macOS. We ran them on Windows 11 in Git Bash, where the interpreter is python.
pip install "voltage-verify>=0.2.2"
curl -fsSLO https://voltagegpu.com/blog/two-proofs/evidence/rtx6000b-2026-09-17/bundle.json
voltage-verify verify bundle.json --challenge d807768657e40ee62d430d9dc5eb924d520ba1d07e351bc44ee59dbe611085a7 --hwmodel GB20X --gpus 1
What it printed on 22 October 2026:
[PASS] manifest.format manifest is well formed
[PASS] manifest.commitments bundle commitments match the manifest
[PASS] manifest.challenge challenge is the one this verifier issued
[PASS] tdx.structure TDX quote v4, TEE 0x81, 4940 bytes
[PASS] tdx.debug TD attributes 0000001000000000 (0x10000000), DEBUG (bit 0) off: not a debug TD
[PASS] tdx.report_data quote report_data equals SHA-512 of the manifest
[PASS] tdx.signatures attestation key, QE binding, QE report and PCK chain verify up to the pinned Intel SGX Root CA
[PASS] tdx.collateral TCB info and QE identity signed by Intel (Intel PCS, fetched now)
[PASS] tdx.tcb platform TCB UpToDate, QE UpToDate, TDX_03 UpToDate
[PASS] tdx.revocation PCK certificate not revoked (57 entries in CRL)
[PASS] tdx.revocation PCK CA certificate not revoked (0 entries in CRL)
[PASS] nvidia.signatures 2 NVIDIA-signed tokens verify, keys from the bundle chained to the pinned NRAS intermediate (NVIDIA's live JWKS fetched for its intermediates)
[PASS] nvidia.nonce NRAS eat_nonce equals SHA-256 of the manifest
[PASS] nvidia.policy overall result true, every GPU: measurements ok, secure boot on, debug off, nonce matched, report signature and chain validated
[PASS] nvidia.freshness token issued 0s from bundle creation
TDX: MRTD eea8b6a814569a52bd1e12f6b869bb2d... TCB UpToDate QE UpToDate
GPU: GPU-0 GB20X driver 595.71.05 vbios 98.02.9E.00.01 measurements success
RESULT: VERIFIED
Fifteen checks pass. This article reads the tdx.* lines. The nvidia.* lines are covered in the bundle tutorial.
Step 2: print every field
With --json, voltage-verify lists the main fields under facts.tdx, not the whole TD report or the certificates. This script prints everything, using the standard library and cryptography, which voltage-verify installs.
"""Print every field of the Intel TDX quote carried by a voltage-verify bundle.
Usage: python3 -I read_quote.py bundle.json
Layout of a TDX quote v4: a 48-byte header, the 584-byte TD report, then the
signature data. Standard library only, plus `cryptography` (installed with
voltage-verify) to read the certificates.
"""
import base64
import hashlib
import json
import struct
import sys
from cryptography import x509
from cryptography.hazmat.primitives import hashes
bundle = json.load(open(sys.argv[1], encoding="utf-8"))
b64 = bundle["tdx"]["quote_b64"]
quote = base64.b64decode(b64 + "=" * (-len(b64) % 4))
version, key_type, tee_type = struct.unpack_from("<HHI", quote, 0)
print(f"header: version {version}, key type {key_type}, TEE type 0x{tee_type:x}, {len(quote)} bytes")
# TD report fields: (name, offset in the quote, size in bytes)
FIELDS = [
("TEE_TCB_SVN", 48, 16), ("MRSEAM", 64, 48), ("MRSIGNERSEAM", 112, 48),
("SEAMATTRIBUTES", 160, 8), ("TDATTRIBUTES", 168, 8), ("XFAM", 176, 8),
("MRTD", 184, 48), ("MRCONFIGID", 232, 48), ("MROWNER", 280, 48),
("MROWNERCONFIG", 328, 48), ("RTMR0", 376, 48), ("RTMR1", 424, 48),
("RTMR2", 472, 48), ("RTMR3", 520, 48), ("REPORTDATA", 568, 64),
]
for name, off, size in FIELDS:
print(f"{name:<14} {quote[off:off + size].hex()}")
attrs = int.from_bytes(quote[168:176], "little")
print(f"TD attributes 0x{attrs:x}: DEBUG (bit 0) = {attrs & 1}, SEPT_VE_DISABLE (bit 28) = {attrs >> 28 & 1}")
canonical = json.dumps(bundle["manifest"], sort_keys=True, separators=(",", ":"), ensure_ascii=False)
print("REPORTDATA == SHA-512(manifest):", hashlib.sha512(canonical.encode()).digest() == quote[568:632])
sig_len = struct.unpack_from("<I", quote, 632)[0]
sig = quote[636:636 + sig_len] # quote signature (64), attestation key (64), certification data
cert_type, cert_len = struct.unpack_from("<HI", sig, 128)
qe = sig[134:134 + cert_len] # QE report (384), its signature (64), auth data, PCK chain
prod_id, isv_svn = struct.unpack_from("<HH", qe, 256)
print(f"signature data: {sig_len} bytes, certification data type {cert_type}")
print(f"QE report: MRSIGNER {qe[128:160].hex()}, ISVPRODID {prod_id}, ISVSVN {isv_svn}")
auth_len = struct.unpack_from("<H", qe, 448)[0]
inner_type, inner_len = struct.unpack_from("<HI", qe, 450 + auth_len)
pem = qe[456 + auth_len:456 + auth_len + inner_len].rstrip(b"\0")
print(f"certification data type {inner_type}:")
for cert in x509.load_pem_x509_certificates(pem):
print(f" {cert.subject.rfc4514_string()} (valid until {cert.not_valid_after_utc:%Y-%m-%d})")
print("root SHA-256:", cert.fingerprint(hashes.SHA256()).hex())
python3 -I read_quote.py bundle.json printed:
header: version 4, key type 2, TEE type 0x81, 4940 bytes
TEE_TCB_SVN 05030400000000000000000000000000
MRSEAM 476a2997c62bccc78370913d0a80b956e3721b24272bc66c4d6307ced4be2865c40e26afac75f12df3425b03eb59ea7c
MRSIGNERSEAM 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
SEAMATTRIBUTES 0000000000000000
TDATTRIBUTES 0000001000000000
XFAM e702060000000000
MRTD eea8b6a814569a52bd1e12f6b869bb2d9c0c8a7a43e658ffc3b42c199f116157ea7f04d359c7fdfd8ac483152cc13542
MRCONFIGID 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
MROWNER 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
MROWNERCONFIG 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
RTMR0 f9ac3522e05572c2ede103eb9f243bebddee62d8e8db65a526736ea2bd5eb6dbe69a5ff8082c8050865b5ddadae4fa8a
RTMR1 965b54adf526d37237906189a31d9b058c39fac8909d9689e3340505aac4176deed2c2f3374b226304b23137d4832ae9
RTMR2 c2f56e0459db5660608f8f3a312f67decc0d210d55e93d3d106fe7f939941c524b0b370d53c4a6d6290e2df3b9511397
RTMR3 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
REPORTDATA 832791479ad739ef2c1d51e1fb1da7a7a1422b6c88afaf2ca1c292f1ae9ee7dbe5e571b9926390cfdd7f62672c696ccda0c004a0c779a30c16ff80ce461790b8
TD attributes 0x10000000: DEBUG (bit 0) = 0, SEPT_VE_DISABLE (bit 28) = 1
REPORTDATA == SHA-512(manifest): True
signature data: 4304 bytes, certification data type 6
QE report: MRSIGNER dc9e2a7c6f948f17474e34a7fc43ed030f7c1563f1babddf6340c82e0e54a8c5, ISVPRODID 2, ISVSVN 7
certification data type 5:
C=US,ST=CA,L=Santa Clara,O=Intel Corporation,CN=Intel SGX PCK Certificate (valid until 2033-03-13)
C=US,ST=CA,L=Santa Clara,O=Intel Corporation,CN=Intel SGX PCK Platform CA (valid until 2033-05-21)
C=US,ST=CA,L=Santa Clara,O=Intel Corporation,CN=Intel SGX Root CA (valid until 2049-12-31)
root SHA-256: 44a0196b2b99f889b8e149e95b807a350e7424964399e885a7cbb8ccfab674d3
The offsets match voltage-verify's parser (TD attributes at byte 168, REPORTDATA at 568), and the sizes add up: 48 + 584 + 4 (a length field) + 4,304 = 4,940 bytes. MRCONFIGID, MROWNER and MROWNERCONFIG, immutable software-defined IDs in Linux's description, are zero: they carry nothing here. We do not interpret XFAM or SEAMATTRIBUTES.
The fields, one by one
MRTD: what the TD started from
Value: eea8b6a8…2cc13542.
The TDX module computes MRTD while the host builds the TD, before the TD runs. Linux documents it as the measurement of the TD's initial contents: its initial configuration and firmware image.
What it proves. The TD started from contents with this hash, measured by the TDX module, not reported by the host.
What it does not prove. That this firmware is one you trust: that needs a reference value, ideally rebuilt from source, and we publish none for this image. Our data only shows stability: the same MRTD appears in all four RTX PRO 6000 bundles we have published.
RTMR0 to RTMR3: the boot chain
Values: RTMR0 f9ac3522…dae4fa8a, RTMR1 965b54ad…d4832ae9, RTMR2 c2f56e04…b9511397, RTMR3 all zeros.
RTMRs are run-time registers that software in the TD can extend, mixing new data into the current value. The UEFI specification (2.10, section 38.4.1), as implemented in the EDK2 firmware, maps PCR 1 and 7 to RTMR0, PCR 2 to 6 to RTMR1 and PCR 8 to 15 to RTMR2. Nothing maps to RTMR3. Typically, RTMR0 holds the firmware configuration, RTMR1 the boot loader and kernel, RTMR2 the kernel command line and initrd.
What they prove. The boot events recorded by firmware and the boot loader hash to these values.
What they do not prove. Which events those were. A hash chain cannot be read backwards: you replay the firmware's event log and compare, and the bundle does not include that log.
The published bundles show the limit. RTMR0 and RTMR1 are identical in all four, RTMR3 is zero in all four, and RTMR2 differs every time:
| Bundle | RTMR2, first 16 hex digits |
|---|---|
| 17 Sep, 00:00 UTC (this one) | c2f56e0459db5660 |
| 17 Sep, 12:28 UTC (deployed by API) | c67f740f73f8d900 |
| 9 Oct | d9d5a5c17828c2b8 |
| 17 Oct (weekly run) | 49b10f1d50c9b0fe |
We have not published the event log that would explain the change. Pinning RTMR2 would have accepted at most one of these VMs. Pinning MRTD, RTMR0 and RTMR1 would have accepted all four; expect them to change with image updates.
REPORTDATA: your challenge
Value: 83279147…461790b8 (64 bytes).
The guest software chooses these 64 bytes. voltage-verify writes there the SHA-512 of the manifest, serialized canonically (keys sorted, no spaces, UTF-8). The manifest holds a 32-byte challenge, here d8077686…611085a7, and the script confirms the hash. The SHA-256 of the same manifest is the nonce in NVIDIA's GPU tokens: that manifest is the only link between the two proofs.
A challenge the bundle was not made for fails (output trimmed):
$ voltage-verify verify bundle.json --offline --challenge 0000000000000000000000000000000000000000000000000000000000000000
[FAIL] manifest.challenge challenge differs from the one this verifier issued (replay or foreign bundle)
RESULT: NOT VERIFIED (manifest.challenge)
What it proves. The quote was requested for this exact manifest. If you generated the challenge, the quote was produced after you asked, not replayed.
What it does not prove. Freshness to you, unless the challenge is yours: here it was drawn inside the VM. Generate yours on your machine; the published script two-proofs-in-the-vm.sh accepts it as CHALLENGE. The field also means only what the guest software decided: our inference run of 16 October puts a SHA-256 of a nonce and the instance's public key in its first 32 bytes.
TD attributes: the debug bit
Value: 0000001000000000, read as a little-endian 64-bit integer: 0x10000000.
Only bit 28 is set. Linux calls it SEPT_VE_DISABLE; in Linux 6.8, a guest not in debug mode panics at boot without it (this guest runs 6.8.0-110-generic). Bit 0, DEBUG, is 0.
A debug TD gives no confidentiality: the host can read and modify its memory and CPU state, and Intel's Quoting Enclave still signs its quote. voltage-verify 0.2.1 and earlier printed this field without checking it. Version 0.2.2, released on 21 October 2026, fails a quote with bit 0 set unless you pass --allow-debug. Here is a copy of the quote with bit 0 flipped:
$ python3 -I -c "import json,base64;s=json.load(open('bundle.json'))['tdx']['quote_b64'];open('quote.bin','wb').write(base64.b64decode(s+'='*(-len(s)%4)))"
$ python3 -I -c "q=bytearray(open('quote.bin','rb').read()); q[168]|=1; open('quote-debug.bin','wb').write(q)"
$ voltage-verify quote quote-debug.bin --offline
[PASS] tdx.structure TDX quote v4, TEE 0x81, 4940 bytes
[FAIL] tdx.debug TD attributes 0100001000000000 (0x10000001), DEBUG (bit 0) ON: a debug TD gives no confidentiality, the host can read and modify its memory
[FAIL] tdx.signatures quote signature does not verify with the attestation key:
TDX: MRTD eea8b6a814569a52bd1e12f6b869bb2d... TCB ? QE ?
RESULT: NOT VERIFIED (tdx.debug, tdx.signatures)
tdx.debug fails because the bit is set; tdx.signatures fails because the attestation key signed the original bytes. A genuine debug TD has a validly signed quote, so only tdx.debug would catch it.
What it proves. The TD was not created in debug mode.
What it does not prove. Anything about the software inside it.
TCB status: is the platform current?
TEE_TCB_SVN, 05030400000000000000000000000000, records the TDX module's security version at TD launch. voltage-verify reads the module's major version from its second byte (03, hence TDX_03) and its security version from the first (05). The PCK certificate adds the CPU's SGX security versions and the FMSPC, 20a06d080000, which identifies the platform family.
Intel publishes signed TCB info per FMSPC: a list of levels, newest first, where the first level the platform meets gives its status. In the copy stored in the bundle (issued 16 September 2026), the UpToDate level, dated 13 August 2025, requires TDX components of at least 05 00 04. This quote has 05 03 04.
Online on 22 October, Intel's current documents give platform TCB UpToDate, QE UpToDate, TDX_03 UpToDate, with no advisory IDs. Offline, the stored documents give the same verdict plus a warning, as they passed their nextUpdate date on 16 October 2026:
[WARN] tdx.collateral_fresh Intel collateral is past its nextUpdate; refetch online
What it proves. On the date of Intel's documents, Intel rated the platform, the TDX module and the Quoting Enclave UpToDate.
What it does not prove. That this lasts. In the same TCB info, the level dated 14 May 2025 is rated OutOfDate. An offline check is only as current as the documents it reads.
The certificate chain: who vouches
The script output ends with the chain: PCK Certificate, PCK Platform CA, Intel SGX Root CA. voltage-verify checks each signature and validity date, and compares the root with the copy of Intel's root it ships, pinned by its SHA-256 (44a0196b…fab674d3). The Quoting Enclave's MRSIGNER (dc9e2a7c…0e54a8c5) and product ID (2) match Intel's signed identity for it, and its security version (7) meets the UpToDate level (4 in the stored identity). Last, the PCK certificate is not among the 57 entries of Intel's revocation list, and the root's list is empty. voltage-verify selftest also alters one byte of the quote body:
[PASS] quote-tamper one byte of the TDX quote body altered -> rejected on tdx.signatures
What it proves. A genuine Intel platform, with an identity Intel issued, signed this quote, and the quote has not changed since.
What it does not prove. Who operates the machine, or where. The certificates name Intel, not a cloud provider.
What this proves, and what it does not
Together, the fields prove that on 17 September 2026 a trust domain, not in debug mode, ran on an Intel platform that Intel rated UpToDate, with the measurements above, and produced this quote for this manifest.
They do not prove:
- that the firmware and kernel are ones you trust: no reference values are published for this image, and RTMR2 changes from one VM to the next;
- anything about the GPU: the NVIDIA tokens are a separate proof, tied to the quote only by the manifest, so the two are not shown to share a machine;
- which code ran after boot: RTMR3 is zero and the manifest names no image;
- freshness to you, since this challenge was drawn inside the VM;
- the state of the TD today: a quote describes the TD when it was produced.
Reproduce it
Tested on 22 October 2026 on Windows 11 (Git Bash, Python 3.12.4), with python for python3 and . vv/Scripts/activate for the venv.
python3 -m venv vv && . vv/bin/activate
pip install "voltage-verify>=0.2.2"
B=https://voltagegpu.com/blog/two-proofs/evidence/rtx6000b-2026-09-17
curl -fsSLO "$B/bundle.json"
curl -fsSLO "$B/SHA256SUMS"
grep ' bundle.json$' SHA256SUMS | sha256sum -c -
C=d807768657e40ee62d430d9dc5eb924d520ba1d07e351bc44ee59dbe611085a7
voltage-verify verify bundle.json --challenge $C --hwmodel GB20X --gpus 1
voltage-verify verify bundle.json --challenge $C --offline --json
voltage-verify selftest bundle.json --offline --challenge $C
python3 -I read_quote.py bundle.json # the script from Step 2
Expected: bundle.json: OK, RESULT: VERIFIED, "ok": true with the tdx.collateral_fresh warning, SELFTEST: PASS, then the fields of Step 2. To compare RTMR2, run the script on the bundles in rtx6000b-api-2026-09-17/ and rtx6000b-2026-10-09/, next to this one, and on the weekly run listed on /proofs.
Further reading
- /proofs: every proof we publish, with the command that rechecks it.
- voltage-verify: what the tool checks, its changelog and its source (MIT).
- Inference proofs, 16 October 2026: the same Intel checks on every instance serving three TEE models, with another REPORTDATA convention.
來源:DEV Community · dev.to