Skip to content

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 m6a SEV-SNP instances, firmware only, --vmm ec2.
  • GCE n2d instances, --vmm gce, at every vCPU count Google endorses.
  • QEMU measured direct boot with -cpu EPYC-v4 or EPYC-Genoa, on Ubuntu's ovmf-amdsev firmware.

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.

  1. 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
    
  2. 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
  • --output needs the quoted registers (--rtmrs or --pcrs): a replay with nothing to compare against proves nothing.
  • --label names the machine or image the replay is for.
  • --observed is 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.