tpm_utils: add a CLI for preparing vTPM NVRAM state blobs - #4400
Ming-Wei Shih (mingweishih) wants to merge 12 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The new CLI/provisioning code has a couple of concrete robustness gaps (unchecked integer narrowing for cert sizing and missing early validation for unsupported v1.85 NVRAM size overrides) that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR introduces a new developer CLI tool (tpm_utils) for preparing and inspecting pre-provisioned vTPM NVRAM state blobs, updates TPM tests to consume a checked-in TPM 1.85 blob instead of synthesizing state at runtime, and promotes the RSA SRK public template into tpm_lib for shared reuse. It also adds Guide documentation for the new tool and wires the crate into the workspace.
Changes:
- Add
tpm_utils(prepare+inspect) to generate/inspect vTPM NVRAM blobs using the reference implementations (feature-gated behindtpm). - Switch TPM 1.85 tests to use a checked-in pre-provisioned blob and simplify common test initialization accordingly.
- Expose
tpm_lib::rsa_srk_template()so both the tool and tests share one SRK template definition.
File summaries
| File | Description |
|---|---|
| vm/devices/tpm/tpm_utils/src/provision.rs | Implements provisioning steps and exports/round-trips the committed NVRAM blob. |
| vm/devices/tpm/tpm_utils/src/main.rs | Adds the feature-gated clap CLI with prepare and inspect subcommands. |
| vm/devices/tpm/tpm_utils/src/inspect.rs | Implements blob inspection (persistent objects + key NV indices). |
| vm/devices/tpm/tpm_utils/src/engine.rs | Wraps the TPM 1.38/1.85 reference libs behind a common engine + callbacks. |
| vm/devices/tpm/tpm_utils/Cargo.toml | Defines the new tool crate and its tpm/vendored feature gating. |
| vm/devices/tpm/tpm_lib/tests/tpm_1_85.rs | Points TPM 1.85 tests at the checked-in pre-provisioned blob. |
| vm/devices/tpm/tpm_lib/tests/tpm_1_38.rs | Renames legacy boolean to a blob constant (v1.38 pre-provisioned state). |
| vm/devices/tpm/tpm_lib/tests/common/mod.rs | Simplifies pre-provisioned TPM init and removes duplicated SRK template. |
| vm/devices/tpm/tpm_lib/src/lib.rs | Promotes the RSA SRK public template into the shared library API. |
| vm/devices/tpm/tpm_device/src/lib.rs | Adds a unit test that boots TPM 1.85 from the checked-in blob and validates owner-defined state. |
| vm/devices/tpm/test_data/README.md | Documents the available blobs and how to regenerate the TPM 1.85 blob using tpm_utils. |
| Guide/src/SUMMARY.md | Adds a Guide entry for the new tpm_utils dev tool page. |
| Guide/src/dev_guide/dev_tools/tpm_utils.md | Documents how to build and use tpm_utils (prepare/write/inspect flows). |
| Cargo.toml | Adds vm/devices/tpm/tpm_utils to workspace members. |
| Cargo.lock | Records the new tpm_utils package in the lockfile. |
Review details
- Files reviewed: 14/16 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
The new CLI needs tighter flag validation to avoid silently ignoring user input, and the new v1.85 blob test should assert AK presence to better detect incomplete/incorrect blobs.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
vm/devices/tpm/tpm_utils/src/main.rs:166
prepareaccepts--ak-cert-index nonewhile still allowing--ak-cert/--ak-cert-index-size; the file is read unconditionally and then silently ignored because provisioning skips index creation. This is confusing for users and can make it look like the cert was embedded when it wasn’t. Reject these flag combinations (or require a non-noneindex kind when--ak-cert/--ak-cert-index-sizeis provided) before reading the file.
vm/devices/tpm/tpm_device/src/lib.rs:2355- The new v1.85 pre-provisioned blob test asserts SRK presence, but doesn’t assert the AK is present even though the blob is expected to contain one (and AK presence is a key part of the provisioning shape). Adding an AK handle assertion would make the test better at catching partial/incorrect blobs.
- Files reviewed: 14/16 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The new CLI currently allows/accepts cert-related flags that become silently ignored under --ak-cert-index none, and the doc-code-sync mapping table entry for the new Guide page/tool path is missing.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
vm/devices/tpm/tpm_utils/src/main.rs:156
--ak-cert-index nonecauses--ak-certand--ak-cert-index-sizeto be silently ignored (and currently still attempts to read the cert file). Add explicit validation so users get a clear error when they supply cert-related args while disabling the index.
Guide/src/dev_guide/dev_tools/tpm_utils.md:4- This new Guide page is added to
Guide/src/SUMMARY.md, but the repo’s doc-code-sync mapping table in.github/skills/guide-maintenance/SKILL.mddoesn’t yet include an entry forvm/devices/tpm/tpm_utils/→dev_guide/dev_tools/tpm_utils.md. Please add that row so future TPM tool changes get correctly flagged for doc updates.
- Files reviewed: 14/16 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
There are a couple of correctness/coverage gaps (mitigation-marker blob validation and clippy coverage for tpm_utils on non-Linux CI) that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
vm/devices/tpm/tpm_utils/src/provision.rs:185
--mitigation-markerprovisionsTPM_NV_INDEX_MITIGATED, but the post-export round-trip validation doesn't assert that the marker index actually made it into the committed blob. This can let a broken export/provisioning path return success and only fail later at VM boot.
- Files reviewed: 19/21 changed files
- Comments generated: 1
- Review effort level: Lite
8a14611 to
f34d29f
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new CLI currently allows incompatible flag combinations that are silently ignored, which can produce surprising blobs without an error.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 19/21 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The new Guide page should be added to the repo’s doc-code-sync mapping table to keep future documentation prompts accurate.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
Guide/src/dev_guide/dev_tools/tpm_utils.md:5
- This new Guide page should be added to the repo’s doc-code-sync mapping table (maintained in
.github/skills/guide-maintenance/SKILL.md) so future code changes undervm/devices/tpm/tpm_utils/get the correct “update the Guide” prompt. Add a mapping row forvm/devices/tpm/tpm_utils/→dev_guide/dev_tools/tpm_utils.md.
- Files reviewed: 19/21 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟢 Approval recommended
The new tool, tests, docs, and CI updates appear internally consistent (including feature gating and regenerated workflow changes) with no verified correctness or maintainability blockers in the reviewed diffs.
Review details
- Files reviewed: 19/21 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The new v1.85 pre-provisioned blob test doesn’t currently verify the imported NV index contents/initialization, leaving the stated “state survives” validation incomplete.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
vm/devices/tpm/tpm_device/src/lib.rs:2370
- The new v1.85 pre-provisioned blob test only asserts that the AK cert NV index exists, is owner-defined, and is 1024 bytes, but it doesn’t verify that the index’s contents are actually present/initialized after booting from the blob. Since this PR’s goal is to validate state import, it would be stronger to read the NV index and assert it’s initialized and matches the known bytes used to generate the checked-in blob.
Guide/src/dev_guide/dev_tools/tpm_utils.md:35 - The SymCrypt table row is very long (single source line), which conflicts with the Guide style guideline to wrap lines at 80 characters. Consider shortening the table cell and moving the extra explanation into prose below the table (and/or using a reference-style link) to keep line lengths reasonable.
- Files reviewed: 20/22 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟢 Approval recommended
The changes are cohesive (tool + tests + docs + CI wiring), follow the existing TPM patterns, and include a targeted device-level test validating the new checked-in 1.85 blob behavior.
Review details
- Files reviewed: 20/22 changed files
- Comments generated: 0 new
- Review effort level: Lite
| | --- | --- | --- | | ||
| | `vTpmState.blob` | 1.38 | The TpmEngFWInit (internal) tool | | ||
| | `vTpmState-corrupt.blob` | 1.38 | `vTpmState.blob`, corrupted by hand | | ||
| | `vTpmState-1.85.blob` | 1.85 | `tpm_utils prepare` | |
There was a problem hiding this comment.
Was this new file created with openssl or symcrypt as the backend? Do things work properly when the blob is created by one and tested against the other?
A vTPM's persistent state is an opaque blob that the reference implementation manufactures and commits, and that OpenVMM/OpenHCL keep in the VMGS TPM_NVRAM (v1.38) or TPM_185_NVRAM (v1.85) file. Until now the only pre-provisioned blob in the tree was produced by an internal tool, so there was no way to build one for v1.85 or to vary what it contains. Add `tpm_utils`, a tool built on `tpm_lib` that drives a reference implementation directly: - `prepare` runs the provisioning commands (AK, SRK, owner-defined or platform-created AK cert index, mitigation marker) and exports the committed NVRAM blob, which can then be written into a VMGS with vmgstool to exercise state import at VM boot. - `inspect` loads an existing blob and reports its persistent objects and NV indices. The tool mirrors the platform callbacks `tpm_device` uses, including the per-version unique value, so its blobs behave the same in a real VM. Use it to generate a checked-in v1.85 pre-provisioned blob and replace the state the tpm_1_85 tests were synthesizing at runtime, and add a `tpm_device` test that boots from that blob. Also promote `rsa_srk_template` into `tpm_lib` so the tool and the tests share one definition. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
Defaulting the index size to the AK cert size narrowed with `as u16`, so a cert larger than 64k silently truncated and then failed with a confusing "does not fit" message. Bound the requested size by the backend's maximum NV index size before narrowing, which also gives a clear error for certs that are too large for the TPM rather than failing inside NV_DefineSpace. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
The TPM accepts a zero-size NV index, so an empty --ak-cert file or an explicit --ak-cert-index-size 0 silently exported a blob whose AK cert index could never hold a cert. Fold the bound into a range check. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
The state a TPM commits is tied to the library that produced it, so the tool should be buildable against the same backend as the build the state is destined for. Replace the hardcoded `openssl` features on the TPM libraries with `openssl` (default) and `symcrypt` features on the tool. The 1.38 library has no SymCrypt backend, so it stays on OpenSSL. These are non-additive: `ms-tcg-tpm-sys` fails its build script when both are enabled. Exclude `tpm_utils` from the workspace-wide `--all-features` clippy run and lint it separately against the default backend, mirroring how the `crypto` crate's backends are covered. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
Windows and macOS clippy runs already use CargoFeatureSet::None, so the non-additive backend features are not a problem there. Only exclude tpm_utils from the workspace run when --all-features is in play. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
--ak-cert and --ak-cert-index-size were silently ignored, exporting a blob with no AK cert index and no indication anything was dropped. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
The 1.85 TPM library requires OpenSSL 3.5, which is newer than the CI images provide, so the dedicated tpm_utils clippy run failed with "OpenSSL 3.5 or newer is required". The workspace run only works because openvmm enables the vendored feature; do the same here. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
The unit test build also uses --all-features, which enables both TPM crypto backends and fails the ms-tcg-tpm-sys build script. tpm_utils has no unit tests, and clippy covers it separately. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
- Reject --auth-value when it has no effect (it only applies to a platform-created AK cert index and the mitigation marker); this needed Option<u64> to tell "unset" from an explicit 0. - Log the error behind an "unreadable" nv index in inspect, rather than discarding it in a tool whose job is diagnosis. - Drop the unreachable! in the AK cert index match and explain why the owner path pads the cert while the platform path does not. - Use pub(crate) consistently in engine.rs. - Assert the AK survives the pre-provisioned blob, not just the SRK. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
The round-trip check covered the AK, SRK, and AK cert index but not the mitigation marker, so prepare could succeed with the marker missing. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
The blob test only checked the AK cert index metadata, so a blob that imported the index but lost its contents would still pass. Read it back and compare against the known bytes. Also split the SymCrypt table cell into prose so the Guide page stays within 80 columns. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
The blobs are consumed by tests built against whichever backend the build selected, so their provenance matters. All of them are OpenSSL-made: the pinned ms-tcg-tpm-sys revision vendors a TPM whose cryptoLibOptions_Symmetric is Ossl only, so no SymCrypt-backed TPM can currently be built. Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
7baf833 to
7ceca34
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
inspect has unresolved gaps in reporting reserved and other persistent TPM state.
Review details
Suppressed comments (4)
Guide/src/SUMMARY.md:56
- The new Guide page is linked here, but the repository's doc-code-sync mapping still has no entry for
vm/devices/tpm/tpm_utils/→dev_guide/dev_tools/tpm_utils.md. Without that row, future audits will not flag changes to this tool; please add the mapping entry alongside this SUMMARY update.
- [tpm_utils](./dev_guide/dev_tools/tpm_utils.md)
vm/devices/tpm/tpm_utils/src/inspect.rs:30
TPM_NV_INDEX_GUEST_ATTESTATION_INPUTis another OpenVMM-reserved NV index (defined intpm_protocoland read bytpm_device), but it is not included here. A blob containing guest attestation input will therefore omit that state frominspect's report, despite the command documenting that it reports the blob's NV indices; add this index to the list.
const NV_INDICES: &[(&str, u32)] = &[
("AK cert", TPM_NV_INDEX_AIK_CERT),
("attestation report", TPM_NV_INDEX_ATTESTATION_REPORT),
("mitigation marker", TPM_NV_INDEX_MITIGATED),
];
vm/devices/tpm/tpm_utils/src/inspect.rs:29
inspectonly probes these three hard-coded handles and NV indices, so any other persistent object or NV index in an imported blob is silently omitted even though the command is documented as reporting the blob's persistent objects and NV indices. Please either enumerate the corresponding TPM handle capabilities or narrow the command/documentation to explicitly say it reports only the known OpenVMM entries.
const OBJECTS: &[(&str, ReservedHandle)] = &[
("AK", TPM_AZURE_AIK_HANDLE),
("SRK", TPM_RSA_SRK_HANDLE),
("guest secret key", TPM_GUEST_SECRET_HANDLE),
];
const NV_INDICES: &[(&str, u32)] = &[
("AK cert", TPM_NV_INDEX_AIK_CERT),
("attestation report", TPM_NV_INDEX_ATTESTATION_REPORT),
("mitigation marker", TPM_NV_INDEX_MITIGATED),
vm/devices/tpm/tpm_utils/src/main.rs:167
- These new CLI validation paths are not covered by tests: the crate is explicitly excluded from nextest and
main.rshas no test module. Add parser/configuration tests for both rejected flag combinations and the valid--mitigation-marker --auth-valuecase, so a future change cannot silently reintroduce invalid blob configurations.
anyhow::ensure!(
ak_cert_index != AkCertIndexKind::None
|| (ak_cert.is_none() && ak_cert_index_size.is_none()),
"--ak-cert and --ak-cert-index-size have no effect with \
--ak-cert-index none"
);
anyhow::ensure!(
auth_value.is_none()
|| ak_cert_index == AkCertIndexKind::Platform
|| mitigation_marker,
"--auth-value only applies to --ak-cert-index platform and \
--mitigation-marker"
);
- Files reviewed: 20/22 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Unresolved review comments and the TPM/CI scope warrant final human review before approval.
Review details
Suppressed comments (2)
Guide/src/dev_guide/dev_tools/tpm_utils.md:4
- The new Guide page is linked from
SUMMARY.md, but the code-to-Guide mapping has novm/devices/tpm/tpm_utils/entry. Without that row, future changes to this crate will not be covered by the documentation-sync audit; please add the crate-to-page mapping (and any corresponding “What to Flag” rule).
`tpm_utils` is a developer tool for preparing and inspecting pre-provisioned
vTPM NVRAM state blobs.
Guide/src/dev_guide/dev_tools/tpm_utils.md:69
- The new
--auth-valueoption is not documented in the tool guide, even though it is the only way to choose the password used by platform-created AK-cert indices and mitigation markers (the CLI defaults it to zero). Please add it to this options list and document that it applies only to those cases, so users can reproduce a non-default authorization value from the guide.
- `--ak-cert-index owner|platform|none` — owner-defined indices mimic an
externally provisioned vTPM; platform-created ones mimic what OpenHCL
allocates at boot.
- `--ak-cert-index-size` — index size, in bytes. Defaults to the AK cert size,
or 4096 when no cert is supplied.
- Files reviewed: 20/22 changed files
- Comments generated: 0 new
- Review effort level: Lite
|
Lets also make sure #4481 gets merged first, and this PR can be rebased on top of it and add a guide page. |
A vTPM's persistent state is an opaque blob that the reference
implementation manufactures and commits, and that OpenVMM/OpenHCL keep in
the VMGS
TPM_NVRAM(v1.38) orTPM_185_NVRAM(v1.85) file. Until now theonly pre-provisioned blob in the tree was produced by an internal tool, so
there was no way to build one for v1.85 or to vary what it contains.
This adds
tpm_utils, a tool built ontpm_libthat drives a referenceimplementation directly:
prepareruns the provisioning commands (AK, SRK, owner-defined orplatform-created AK cert index, mitigation marker) and exports the
committed NVRAM blob, which can then be written into a VMGS with
vmgstoolto exercise state import at VM boot.inspectloads an existing blob and reports its persistent objects andNV indices.
The tool mirrors the platform callbacks
tpm_deviceuses, including theper-version unique value, so its blobs behave the same in a real VM.
It is feature-gated behind
tpm(same pattern astpm_device) because thereference implementations need an OpenSSL crypto backend, which isn't
available everywhere the workspace is built.
Follow-up to #4022, which left a TODO to create a pre-provisioned state for
TPM 1.85 (#4022 (comment)).
The tool is used to generate a checked-in v1.85 blob, replacing the state
the
tpm_1_85tests were synthesizing at runtime.rsa_srk_templateis promoted intotpm_libso the tool and the testsshare one definition.
Validation
tpm_utils inspectagainst the existing internal-tool blob reports the AKand SRK with matching attributes and a 1616-byte owner-defined AK cert
index, confirming it reads real provisioned state.
vmgstool write --file-id TPM_185_NVRAM.tpm_device::tests::test_pre_provisioned_nvram_blob_for_v185boots aTpmfrom the checked-in blob and asserts its owner-defined statesurvives.
The checked-in v1.85 blob is 128 KiB, the size that library is compiled for;
v1.85 rejects any other NVRAM size.
A VMM test that boots a full VM from a prepared VMGS is left for a future PR.