Compute expected measurements¶
A fleet verifies its hosts against the measurements you pin in its policy. untrust
measure computes those values from your build artifacts, offline, so you can pin them
before you deploy.
Do not pin a guest's first report
Copying a measurement from the first report a guest sends pins whatever booted, including a tampered image. Compute the value from the artifacts you built, then pin it.
| Command | Computes or checks |
|---|---|
measure snp |
The AMD SEV-SNP launch measurement. |
measure tdx |
The Intel TDX MRTD. |
measure launch |
The SEV-SNP or TDX measurement for a launch-inputs manifest. |
measure gce-endorsement |
Google's signed expected values for a GCE confidential VM. |
measure tdx-eventlog |
A TDX boot, by replaying its event log to the quoted RTMRs. |
measure tpm-eventlog |
A TPM measured boot, by replaying its event log to the quoted PCRs. |
measure ibm-se-tags |
The boot header tags of an IBM Secure Execution image. |
Every option is listed in the CLI reference.
measure snp¶
Computes the expected AMD SEV-SNP launch MEASUREMENT for a guest.
| Input | Meaning |
|---|---|
--ovmf |
The OVMF firmware the guest boots: an SEV (AmdSev) build. |
--vcpus |
The guest's vCPU count, 1 to 512. |
--vmm |
qemu (default), ec2 or gce. It sets the initial vCPU state. |
--vcpu-type or --vcpu-sig |
QEMU only: the -cpu model (for example EPYC-Milan) or the raw CPU signature, because the CPU signature is part of what is measured. |
--kernel, --initrd, --append |
Optional, for measured direct boot. Needs an OVMF built with kernel hashes, which the AmdSev build is. |
--guest-features |
The guest's SEV features (default 0x1). |
--ovmf-hash |
A published 96-hex OVMF digest to use instead of hashing the file. The JSON record notes whether it matches the file. |
It prints the measurement as 96 hex characters. --json prints the full record.
QEMU guest with measured direct boot:
untrust measure snp --ovmf OVMF.amdsev.fd --vcpus 4 --vcpu-type EPYC-Milan \
--kernel vmlinuz --initrd initrd.img --append "console=ttyS0 root=/dev/vda"
EC2 guest, using the firmware AWS publishes for SEV-SNP instances:
untrust measure snp --ovmf ovmf_img.fd --vcpus 2 --vmm ec2
These recipes have been matched against measurements from real hardware:
- EC2
m6aSEV-SNP instances, firmware only,--vmm ec2. - GCE
n2dinstances,--vmm gce, at every vCPU count Google endorses. - QEMU measured direct boot with
-cpu EPYC-v4orEPYC-Genoa, on Ubuntu'sovmf-amdsevfirmware.
QEMU firmware-only boot and other -cpu models have not been matched yet. Confirm the
value against one guest before you pin it.
measure tdx¶
Computes the expected Intel TDX MRTD for a TDVF firmware image.
--firmware is the single combined image QEMU loads with -bios. A split OVMF_CODE
image is refused.
untrust measure tdx --firmware OVMF.tdx.fd
It prints the MRTD as 96 hex characters; --json prints the full record. This recipe
reproduces the MRTD of a real GCP c3 TDX quote from Google's endorsed firmware.
What MRTD does not cover:
- The kernel, initrd and command line of a direct boot. They are measured into RTMR[1]
and RTMR[2]; check them with
measure tdx-eventlog. - MRCONFIGID, MROWNER, the TD attributes and XFAM.
Not supported: the VMM variant that measures all memory regions, and firmware sections whose raw size differs from their size in memory.
measure launch¶
Computes the expected measurement from a launch-inputs manifest. It uses the same code as
check LAUNCH-01, so the value it prints is exactly the value that check compares.
{"schema": "untrust.launch-inputs/v1", "platform": "sev-snp",
"firmware": "/var/lib/vms/OVMF.amdsev.fd", "firmware_sha256": "<optional pin>",
"vmm": "qemu", "vcpus": 4, "vcpu_type": "EPYC-Milan",
"kernel": "/var/lib/vms/vmlinuz", "initrd": "/var/lib/vms/initrd.img", "append": "console=ttyS0"}
For TDX, only firmware and its optional firmware_sha256 pin matter.
untrust measure launch launch-inputs.json
When the recipe has not been matched against real hardware, it warns on standard error:
confirm it against one guest before pinning. --json adds a recipe object with
hardware_matched.
measure gce-endorsement¶
Verifies a Google-signed launch endorsement for a GCE confidential VM and prints the expected values it carries.
-
Download the endorsement named by the measurement a guest reports:
https://storage.googleapis.com/gce_tcb_integrity/ovmf_x64_csm/sevsnp/<MEASUREMENT>.binarypb https://storage.googleapis.com/gce_tcb_integrity/ovmf_x64_csm/tdx/<MRTD>.binarypb -
Verify it, and recompute from the firmware it names:
untrust measure gce-endorsement --endorsement E.binarypb --firmware ovmf.fd --vcpus 2
untrust checks the RSA-PSS SHA-256 signature by the GCE-uefi-signer certificate in the
endorsement, and the chain to Google's GCE-cc-tcb-root, whose SHA-256 is pinned in
untrust. Google publishes that root at
https://pki.goog/cloud_integrity/GCE-cc-tcb-root_1.crt.
The output has one line per value:
signature verified
firmware sha384 <hex>
sev-snp vcpus=2 <measurement>
firmware_sha384 match
snp_recomputed match
A TDX endorsement prints tdx mrtd <hex> and tdx_recomputed instead. The command
exits 1 unless the signature is verified and every recomputed value matches. For SEV-SNP,
--vcpus must be one of the counts Google endorses.
Values in angle brackets are placeholders.
measure tdx-eventlog¶
Checks a TDX boot by replaying its event log. RTMR[0] includes events the VMM generates, so RTMRs are checked by replay rather than predicted.
| Input | Meaning |
|---|---|
--ccel |
The TD's event log, /sys/firmware/acpi/tables/data/CCEL. |
--rtmrs |
RTMR[0..2] or RTMR[0..3] from the verified quote: three or four comma-separated values of 96 hex characters each. |
--kernel, --initrd, --append |
Optional: the kernel, initrd and command line you expect. |
It checks that the log replays to each quoted RTMR, and finds:
- the kernel's Authenticode SHA-384 in RTMR[1];
- the initrd's SHA-384, as the Linux "initrd" event, in RTMR[2];
- the command line in RTMR[2], reporting which encoding matched.
A kernel hash recorded by grub is reported as grub_file_event. RTMR[3] is extended at
runtime, so it reads not-in-log, which is never a match.
untrust measure tdx-eventlog --ccel CCEL --rtmrs "$R0,$R1,$R2" \
--kernel vmlinuz --initrd initrd.img --append "console=ttyS0 root=/dev/vda"
It prints one line per check, for example rtmr0 match or kernel match, and exits 0
only if every requested check matches.
measure tpm-eventlog¶
Checks a TPM measured boot by replaying the firmware's event log to the quoted PCRs.
| Input | Meaning |
|---|---|
--log |
The event log, /sys/kernel/security/tpm0/binary_bios_measurements. |
--pcrs |
The quoted PCR values as JSON: {"sha256": {"0": "<hex>", ...}}. |
--bank |
sha256 (default), sha384 or sha1. |
--kernel, --initrd, --append |
Optional: the kernel, initrd and command line you expect. |
It finds:
- the kernel's Authenticode hash in PCR4 (grub's file hash in PCR9 is reported as
grub_file_event); - the initrd in PCR9;
- the command line in PCR8 (grub's
kernel_cmdline:event) or in PCR9 or PCR12 (the Linux stub's load options).
A quoted PCR that the log never extends reads not-in-log, which is never a match.
untrust measure tpm-eventlog --log binary_bios_measurements --pcrs pcrs.json \
--kernel vmlinuz --initrd initrd.img
It prints one line per check and exits 0 only if every check matches.
It does not check the quote's signature or where the attestation key came from. The fleet verifier checks those for enrolled collectors.
measure ibm-se-tags¶
Prints the boot header tags of an IBM Secure Execution image: the values the Ultravisor's attestation covers.
untrust measure ibm-se-tags se-image.img
The argument is the SE boot image, or its header extracted with pvextract-hdr. It prints
416 hex characters; the last 32 are the SE header tag.
Pin the values in a fleet¶
Pins go in the fleet's policy: open Assets & environments › Environments › Hardware fleets, select the fleet and edit its policy (administrator). Enter one value per line.
| Platform | Field | Format | Check |
|---|---|---|---|
| AMD SEV-SNP | Expected launch measurements | 96 hex characters | SNP-MEAS-01 |
| Intel TDX | Expected TD images: MRTD | 96 hex characters | TDX-MEAS-01 |
| Intel SGX | Expected enclaves: MRENCLAVE | 64 hex characters | SGX-MEAS-01 |
| AWS Nitro Enclaves | Expected enclave images: PCR0 | 96 hex characters, printed by nitro-cli build-enclave |
NITRO-MEAS-01 |
| Arm CCA | Expected realms: initial measurement, RIM | Hex | CCA-MEAS-01 |
| IBM Secure Execution | Expected SE images | 416 hex characters, from measure ibm-se-tags |
SE-MEAS-01 |
- A fleet holds at most 32 pins.
- An empty list means nothing is pinned, and hosts fail closed until it is filled.
- The fleet verifier compares the pins on every report whose signature, certificate chain
and TCB it has verified. That is a stronger check than
LAUNCH-01, which compares against values the host reported.
Bind your KMS or key-broker release policy to the same measurement, so a key is released only to the image you pinned. The Key binding page and the Enforce at key release → link in Reported claims show whether keys are bound.
Two-administrator approval¶
A fleet can turn on pin approval, so no single administrator can change what it trusts.
With pin approval on:
- One administrator can remove pins on their own, but never the last one.
- Adding or replacing a pin, clearing the last pin, or turning approval off needs a pin request: the value, the hardware it was seen on and a reason. A different administrator must approve it.
- Approving needs a signed-in session. An API key can propose, reject or cancel a request, never approve one.
- A request expires after 7 days.
- Pin approval does not cover IBM Secure Execution fleets.
In the console, use Propose pin, Approve and Reject under Platform & TCB. The Re-baseline → <fleet> pins link in a Reported claims drawer starts a change from a host you are looking at. The fleet's pin history records who added or removed each pin and who approved it.
Upload event-log replays from CI¶
measure tdx-eventlog and measure tpm-eventlog can write their result as an
untrust.boot-replay/v1 document, so a pipeline can send boot evidence to the console:
untrust measure tdx-eventlog --ccel CCEL --rtmrs "$R0,$R1,$R2" \
--kernel vmlinuz --initrd initrd.img \
--output replay.json --label "build-host-07" --observed 2026-10-06T03:21:00Z
python -m untrust.enterprise_ci_client --endpoint "$UNTRUST_SUBMIT_ENDPOINT" --github-oidc \
--replay replay.json
--outputneeds the quoted registers (--rtmrsor--pcrs): a replay with nothing to compare against proves nothing.--labelnames the machine or image the replay is for.--observedis when the log and registers were captured, in ISO 8601 with a UTC offset, and not in the future. It defaults to now; set it when you replay an earlier capture, so the document is not presented as fresh evidence.
The CI binding must allow the replay evidence kind; see
Send evidence from CI. The service checks the document again and
recomputes the verdict itself rather than trusting the one in the file.