Skip to content

Include ID block when launching guests#247

Draft
markg-github wants to merge 14 commits into
AMDEPYC:mainfrom
markg-github:pr/id-block
Draft

Include ID block when launching guests#247
markg-github wants to merge 14 commits into
AMDEPYC:mainfrom
markg-github:pr/id-block

Conversation

@markg-github

Copy link
Copy Markdown
Contributor

ID block includes expected measurement, guest policy, Family ID, Image ID, etc. The expected measurement must match the calculated measurement. Note that sev-certify has always calculated an expected measurement even though it's only now, with this PR, that an ID block is included when launching guests. Ignoring the ID block, sev-certify used the expected measurement as "host data". This is still the case.

ID blocks are signed, but they can be self-signed, which is what this PR does.

Finally, there's a simple tool that allows user specification of some of the fields in the ID block. Just open tools/id-block-builder.html in a browser.

Copilot AI review requested due to automatic review settings May 28, 2026 15:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds SEV-SNP ID block generation and launch integration so guests can be launched with a signed ID block containing measurement, policy, and metadata.

Changes:

  • Adds a host-side generate-id-block module and service to patch/sign id-block.b64.
  • Updates guest launch to pass policy, id-block, and id-auth to QEMU.
  • Adds a browser-based ID block template builder and related documentation.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/id-block-README.md Documents the ID block builder and default policy/template.
tools/id-block-builder.html Adds browser UI for generating unsigned ID block templates.
modules/report/host/display-guest-logs/.../display-guest-logs.sh Adds timeout messaging for guest test log display.
modules/launch/host/mkosi.conf Includes the new generate-id-block module.
modules/launch/host/launch-guest/.../launch-guest.service Orders guest launch after ID block generation.
modules/launch/host/launch-guest/.../launch-guest.sh Builds QEMU command dynamically and adds ID block arguments.
modules/launch/host/launch-guest/.../id-block.b64 Adds default unsigned ID block template.
modules/launch/host/launch-done/.../launch-done.service Adds ID block generation to launch completion dependencies.
modules/launch/host/generate-id-block/README.md Documents runtime ID block patching/signing.
modules/launch/host/generate-id-block/.../generate-id-block.service Adds oneshot service for ID block generation.
modules/launch/host/generate-id-block/.../generate_id_block.py Implements measurement patching, ECDSA signing, and ID auth generation.
modules/launch/host/generate-id-block/mkosi.conf Adds cryptography dependency for host image.
modules/build/guest/mkosi.conf Adds Python package to guest build configuration.
.github/workflows/build-and-release.yml Adds release job dependency to build job.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/build-and-release.yml
Comment thread tools/id-block-builder.html Outdated
Comment thread tools/id-block-builder.html Outdated
Comment thread tools/id-block-builder.html Outdated
Copilot AI review requested due to automatic review settings June 1, 2026 22:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread tools/id-block-builder.html Outdated
Comment thread tools/id-block-builder.html Outdated
Comment on lines +306 to +310
function dl(content, name, type) {
const url = URL.createObjectURL(new Blob([content], {type}));
Object.assign(document.createElement('a'), {href:url, download:name}).click();
URL.revokeObjectURL(url);
}
Comment on lines +50 to +54
# Extract policy from id-block (bytes 88-95, LE u64) so LAUNCH_START and
# LAUNCH_FINISH see the same value; without this QEMU uses its own default.
POLICY=$(base64 -d "${ID_BLOCK_FILE}" | python3 -c \
"import sys; d=sys.stdin.buffer.read(); print(hex(int.from_bytes(d[88:96],'little')))")
SEV_SNP_OBJECT="${SEV_SNP_OBJECT},policy=${POLICY},id-block=${ID_BLOCK_B64},id-auth=${ID_AUTH_B64}"
Copilot AI review requested due to automatic review settings June 2, 2026 12:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread tools/id-block-README.md Outdated

The most permissive valid policy on the test platform is bits 16+17 set, all
else clear. The tool defaults to this value (`00000000000b` in the 48-bit hex
input, yielding full policy `0x000000000000b0000`).
Comment on lines +1 to +3
[Unit]
Description=Patch guest measurement into id-block.b64
DefaultDependencies=no
Comment thread .github/workflows/build-and-release.yml Outdated
Comment on lines +65 to +66
needs: create-release
if: ${{ always() && (github.event_name == 'pull_request' || needs.create-release.result == 'success') }}
Comment on lines +14 to +22
1. Reads the guest measurement from `guest_measurement.txt` (48-byte SHA-384,
written as `0x<96 hex chars>`)
2. Decodes the ID block template from `id-block.b64` (must be exactly 96 bytes)
3. Patches bytes 0–47 (the `ld` field) with the actual guest measurement
4. Generates an ephemeral P-384 key pair
5. Signs the patched ID block with ECDSA-P384-SHA384
6. Writes the signed ID block back to `id-block.b64`
7. Writes a 4096-byte `ID_AUTH_INFO` structure to `id-auth.b64` containing the
signature and the ephemeral public key (no author key)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good approach. I don't mind keeping this approach but snpguest actually provides functionality to generate the id-block and the id-auth. Also allowing to pass the measurement, familiy id, svn and policy you want to load into the id-block.

Comment thread tools/id-block-README.md Outdated
Comment on lines +3 to +4
Browser-based tool for building unsigned ID block templates for SEV-SNP guest
launch. Opens locally — no server needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a really cool tool! Again I'm sorry I didn't let you know that snpguest could actually calculate it, and that will probably work best for testing, but I wonder if there's somewhere we can place this work.

@markg-github markg-github marked this pull request as draft June 26, 2026 12:08
Copilot AI review requested due to automatic review settings June 26, 2026 12:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Comment on lines +52 to +60
POLICY=$(base64 -d "${ID_BLOCK_FILE}" | python3 -c "
import sys
d = sys.stdin.buffer.read()
n = len(d)
if n != 96:
print(f'ERROR: id-block decoded to {n} bytes (expected 96)', file=sys.stderr)
sys.exit(1)
print(hex(int.from_bytes(d[88:96], 'little')))
")
Comment on lines +69 to +73
# Read metadata from environment, falling back to defaults
family_id = os.environ.get("ID_BLOCK_FAMILY_ID", DEFAULT_FAMILY_ID)
image_id = os.environ.get("ID_BLOCK_IMAGE_ID", DEFAULT_IMAGE_ID)
guest_svn = os.environ.get("ID_BLOCK_GUEST_SVN", DEFAULT_GUEST_SVN)
policy = os.environ.get("ID_BLOCK_POLICY", DEFAULT_POLICY)
Comment on lines +98 to +99
result = subprocess.run(cmd, capture_output=True, text=True)
# Temp files are removed when the TemporaryDirectory context exits
Copilot AI review requested due to automatic review settings June 29, 2026 15:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Comment on lines +13 to +14
Environment=ID_BLOCK_FAMILY_ID=sev-certify-fam0
Environment=ID_BLOCK_IMAGE_ID=sev-certify-img0
Comment on lines +32 to +36
# Metadata defaults (match the committed template values documented in DESIGN.md)
DEFAULT_FAMILY_ID = "sev-certify-fam0"
DEFAULT_IMAGE_ID = "sev-certify-img0"
DEFAULT_GUEST_SVN = "48"
DEFAULT_POLICY = "0xb0000"
Override any of these with a systemd drop-in (`systemctl edit generate-id-block`)
without modifying the script or service file.

For the rationale behind the default values see `DESIGN.md` in this workspace.
Comment thread CLAUDE.md
launch-done.service
```

If `calculate-measurement.service` is skipped (no AMDSEV OVMF), `guest_measurement.txt` is absent. `generate-id-block.service` detects this, exits 0, and `launch-guest.sh` launches without an ID block.
Comment thread CLAUDE.md

- **Additive principle**: ID block support must not cause failures that would not have occurred without it. This is why absent `guest_measurement.txt` causes exit 0 (not 1).
- **Ephemeral keys**: Deliberate — for benchmark/test use, not production attestation. The signature satisfies firmware's structural requirement, not external verifiability.
- See `../DESIGN.md` (workspace-level) for full rationale on policy bit choices and why the DEBUG bit (19) is set.
Comment on lines +46 to +47
# If the measurement file doesn't exist, calculate-measurement.service
# was skipped (e.g. AMDSEV OVMF not present). Nothing to do.
Comment on lines +41 to +49
guest_measurement_sha256sum=$(echo "${calculated_measurement_hex}" | sha256sum | cut -d ' ' -f 1 | xxd -r -p | base64)
dbg "Measurement (hex): ${calculated_measurement_hex}"
dbg "Measurement (sha256): ${guest_measurement_sha256sum}"

# Convert Measurement to the appropriate sha format to pass in as host data
calculated_measurement_hex=$(awk -F "0x" '{print $2}' "${MEASUREMENT_FILE}" )
guest_measurement_sha256sum=$(echo "${calculated_measurement_hex}" | sha256sum | cut -d ' ' -f 1 | xxd -r -p | base64 )
# Build sev-snp-guest object; append ID block args if files are present
SEV_SNP_OBJECT="sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on,host-data=${guest_measurement_sha256sum}"
if [ -f "${ID_BLOCK_FILE}" ] && [ -f "${ID_AUTH_FILE}" ]; then
ID_BLOCK_B64=$(cat "${ID_BLOCK_FILE}")
ID_AUTH_B64=$(cat "${ID_AUTH_FILE}")
Copilot AI review requested due to automatic review settings June 29, 2026 17:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 8 comments.

Comment on lines +7 to +13
# Print prompt to tty1
echo "Tests complete. System will reboot in $TIMEOUT seconds." > /dev/$TTY
echo "Press any key to cancel reboot and drop into root shell..." > /dev/$TTY
# echo "Tests complete. System will reboot in $TIMEOUT seconds." > /dev/$TTY
# echo "Press any key to cancel reboot and drop into root shell..." > /dev/$TTY

# Wait for keypress on tty1
if read -t "$TIMEOUT" -n 1 < /dev/$TTY; then
echo "Key pressed — reboot cancelled." > /dev/$TTY
# if read -t "$TIMEOUT" -n 1 < /dev/$TTY; then
# echo "Key pressed — reboot cancelled." > /dev/$TTY
Comment on lines +47 to +49
if [ -f "${ID_BLOCK_FILE}" ] && [ -f "${ID_AUTH_FILE}" ]; then
ID_BLOCK_B64=$(cat "${ID_BLOCK_FILE}")
ID_AUTH_B64=$(cat "${ID_AUTH_FILE}")
Comment on lines +10 to +12
# ID block metadata — override any of these to change what is embedded in the
# signed block without modifying the script. Defaults match the benchmark
# platform configuration documented in DESIGN.md.
Comment on lines +30 to +33
| `ID_BLOCK_FAMILY_ID` | `0000000000000000000000000000fad0` | 16-byte family ID (32 hex chars) |
| `ID_BLOCK_IMAGE_ID` | `0000000000000000000000000000aed0` | 16-byte image ID (32 hex chars) |
| `ID_BLOCK_GUEST_SVN` | `48` | Guest security version number |
| `ID_BLOCK_POLICY` | `0xb0000` | Guest policy flags (bits 16+17+19) |
Override any of these with a systemd drop-in (`systemctl edit generate-id-block`)
without modifying the script or service file.

For the rationale behind the default values see `DESIGN.md` in this workspace.
Comment on lines +8 to +13
Metadata (family_id, image_id, guest_svn, policy) is read from environment
variables with defaults chosen for the benchmark test platform:
ID_BLOCK_FAMILY_ID — 32 hex chars (default: 0000000000000000000000000000fad0)
ID_BLOCK_IMAGE_ID — 32 hex chars (default: 0000000000000000000000000000aed0)
ID_BLOCK_GUEST_SVN — decimal integer (default: 48)
ID_BLOCK_POLICY — decimal or 0x-prefixed hex (default: 0xb0000)
Comment thread CLAUDE.md Outdated
Comment on lines +53 to +56
| `ID_BLOCK_FAMILY_ID` | `0000000000000000000000000000fad0` | 32 hex chars |
| `ID_BLOCK_IMAGE_ID` | `0000000000000000000000000000aed0` | 32 hex chars |
| `ID_BLOCK_GUEST_SVN` | `48` | Decimal |
| `ID_BLOCK_POLICY` | `0xb0000` | Bits 16 (SMT), 17 (MBO), 19 (DEBUG) |
Comment thread CLAUDE.md

- **Additive principle**: ID block support must not cause failures that would not have occurred without it. This is why absent `guest_measurement.txt` causes exit 0 (not 1).
- **Ephemeral keys**: Deliberate — for benchmark/test use, not production attestation. The signature satisfies firmware's structural requirement, not external verifiability.
- See `../DESIGN.md` (workspace-level) for full rationale on policy bit choices and why the DEBUG bit (19) is set.
Copilot AI review requested due to automatic review settings June 29, 2026 19:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

Comment on lines +10 to +11
ID_BLOCK_FAMILY_ID — 32 hex chars (default: 0000000000000000000000000000fad0)
ID_BLOCK_IMAGE_ID — 32 hex chars (default: 0000000000000000000000000000aed0)
Comment on lines +30 to +31
| `ID_BLOCK_FAMILY_ID` | `0000000000000000000000000000fad0` | 16-byte family ID (32 hex chars) |
| `ID_BLOCK_IMAGE_ID` | `0000000000000000000000000000aed0` | 16-byte image ID (32 hex chars) |
Override any of these with a systemd drop-in (`systemctl edit generate-id-block`)
without modifying the script or service file.

For the rationale behind the default values see `DESIGN.md` in this workspace.
Comment on lines +10 to +12
# ID block metadata — override any of these to change what is embedded in the
# signed block without modifying the script. Defaults match the benchmark
# platform configuration documented in DESIGN.md.
Comment thread CLAUDE.md
Comment on lines +62 to +66
- See `../DESIGN.md` (workspace-level) for full rationale on policy bit choices and why the DEBUG bit (19) is set.

## Cross-Repo Context

This branch (`pr/id-block`) is part of a workspace at `~/code/git/features/id-block/` comparing this implementation against `virtee/snpguest` (in the sibling `virtee/` directory). The workspace `CLAUDE.md` and `DESIGN.md` explain the comparison goals and key differences.
@@ -1,5 +1,6 @@
[Include]
Include=./guest-measurement
Include=./generate-id-block
markg-github and others added 6 commits July 1, 2026 10:21
- add guest policy to QEMU command
- add ID block service logs to certificates
- check for presence of measurement file in new ID block service
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
markg-github and others added 7 commits July 1, 2026 10:21
Policy extraction from id-block bytes 88-95 was done via a python3 -c
heredoc. Replace with od/tr/printf: decode to a flat hex string, validate
the 192-char length (96 bytes), slice bytes 88-95 at offset 176, reverse
the 8 byte-pairs to convert little-endian to big-endian, then print with
printf '0x%x'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds shared callables (calculate_measurement, generate_id_block) in
sev_verify/id_block.py for use by any test that requires an ID block.
Extends VMProfile with id_block/id_auth fields so vm_launch passes
them to QEMU when present. Fixes the step loop in cli.py so callable
steps can update ctx.profile before vm_launch sees it.

Adds a derived-keys placeholder test at cert level 3.0.0-2 that
demonstrates the ID block step pattern and will receive the actual
derived key test steps in a follow-on PR.
Copilot AI review requested due to automatic review settings July 8, 2026 20:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 20 changed files in this pull request and generated 5 comments.

Comment thread sev_verify/vm_profile.py
Comment on lines +284 to +286
if profile.id_block and profile.id_auth:
parts.append(f"id-block={profile.id_block}")
parts.append(f"id-auth={profile.id_auth}")
Comment thread sev_verify/id_block.py
id_block_b64 = id_block_file.read_text().strip()
id_auth_b64 = id_auth_file.read_text().strip()

ctx.profile = replace(ctx.profile, id_block=id_block_b64, id_auth=id_auth_b64)
Comment thread sev_verify/id_block.py
)

from .models import StepContext, StepHandlerResult
from .vm_profile import VMProfile, VMProfileError
Comment on lines +30 to +33
| `ID_BLOCK_FAMILY_ID` | `0000000000000000000000000000fad0` | 16-byte family ID (32 hex chars) |
| `ID_BLOCK_IMAGE_ID` | `0000000000000000000000000000aed0` | 16-byte image ID (32 hex chars) |
| `ID_BLOCK_GUEST_SVN` | `48` | Guest security version number |
| `ID_BLOCK_POLICY` | `0xb0000` | Guest policy flags (bits 16+17+19) |
Comment on lines +8 to +13
Metadata (family_id, image_id, guest_svn, policy) is read from environment
variables with defaults chosen for the benchmark test platform:
ID_BLOCK_FAMILY_ID — 32 hex chars (default: 0000000000000000000000000000fad0)
ID_BLOCK_IMAGE_ID — 32 hex chars (default: 0000000000000000000000000000aed0)
ID_BLOCK_GUEST_SVN — decimal integer (default: 48)
ID_BLOCK_POLICY — decimal or 0x-prefixed hex (default: 0xb0000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants