wasm-verification-component is the TrustMee verifier host for Wasm verification components. It reads a TrustMee CMW input, extracts the TrustMee-profile EAT evidence, loads a stapled verification component when present, or resolves the matching component from an OCI repository and caches Wasm verification components locally.
Normative format documents:
TRUSTMEE_EAT_PROFILE.mdTRUSTMEE_OUTPUT_EAT_PROFILE.mdTRUSTMEE_CMW_COLLECTION_TYPE.md
- TrustMee mainline is a modified Trustee implementation that integrates TrustMee as a verifier driver and uses this repository as its verification library.
- wasm-verification-components contains the Wasm verification components that this verifier host can execute.
The primary input is a CMW Collection that contains:
- exactly one TrustMee-profile EAT Evidence item
- zero or more endorsements
- optionally a stapled Wasm verification component as an endorsement
TrustMee CMW verification returns a JSON output envelope documented in
TRUSTMEE_OUTPUT_EAT_PROFILE.md.
The TrustMee EAT payload carries:
component_idevidenceevidence_type
If the matching Wasm verification component is not stapled into the CMW, the host resolves it from:
- compiled-in placeholder OCI base:
oci://registry.example.com/trustmee/verifier-components - optional override:
--component-repository-hint - recommended deployment base:
oci://ghcr.io/<github-owner>/trustmee-verifier-components
cargo run -p wasm-verification-component -- \
--input <path-to-cmw-file> \
--component-repository-hint <oci-base> \
--component-trust-store <trust-store.json> \
--cache-dir <cache-dir> \
--compactWhen --component-trust-store is provided, the library verifies embedded verifier-component signatures with wasmsign2 before executing the component.
Trust store JSON:
{
"signers": [
{
"public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n",
"fuel": -1,
"allow_network": true,
"valid_until": "2026-12-31T23:59:59Z"
}
]
}Notes:
public_keyaccepts PEM or OpenSSH text. Hex, base64, and base64url encodings of rawwasmsign2key bytes are accepted too.fuel = -1means unlimited Wasmtime fuel. Any other value must be a non-negative integer.valid_untilmust be an RFC3339 UTC timestamp for the trust-store signer entry.- Signed components must also carry embedded TrustMee signature expiry metadata. Use
wasm-verification-components'trustmee-component-signertool to add--signature-expires-atbefore signing withwasmsign2.
Execution policy:
- CMW verification is restrictive by default.
- An unsigned component runs with
1_000_000_000Wasmtime fuel and no outbound network access. - A signed component must verify against exactly one trusted, unexpired signer entry, and its embedded signature expiry metadata must be present and unexpired. The signer entry decides the
fuellimit and whether outbound network access is allowed. - If a signature is present but invalid, missing expiry metadata, expired, untrusted, or ambiguous, verification fails before the component is instantiated.
- Direct
verify_bytesandverify_pathscalls keep legacy behavior unless a trust store is explicitly supplied. - Result claim
verifier_component_sha256is computed over the original component bytes after stripping the embedded signature section and TrustMee signature-expiry metadata. When a signature is validated,verifier_component_signature_public_keycarries the trusted public key used for that validation. - CMW component cache identity still uses the exact
component_iddigest from the input, including embedded signature and expiry metadata.
TrustMee can identify an unstapled verifier component in two ways:
component-<sha256-hex>: content-addressed hash form. The host maps the hash to a package version and verifies that fetched bytes hash back to the samecomponent_id.oci://...: locator form. Thecomponent_idis an OCI URL, and the host fetches the artifact named by that URL. If the URL omits:<semver>, the host probes the registry and selects the highest non-yanked semver version currently published.
Use the hash form when the attestation input must be tied to exact bytes. Use the locator form when you want TrustMee to follow registry updates, usually with a component-signature trust store or a policy that accepts the resolved component hash.
For hash-form IDs, the host maps the digest onto wasm_pkg_client package
coordinates at fetch time:
- repository base:
oci://<registry>/<prefix...>/<namespace>/<package> - Wasm package ref:
<namespace>:<package> - OCI namespace prefix:
<prefix...>/when extra path segments are present before the final two segments - component version:
component_id = component-<sha256>maps to package version0.0.0-component.sha<sha256>
Examples:
oci://ghcr.io/acme/trustmee-verifier-components- package:
acme:trustmee-verifier-components - version for a component digest:
0.0.0-component.sha0123...
- package:
oci://ghcr.io/webassembly/acme/trustmee-verifier-components- package:
acme:trustmee-verifier-components - namespace prefix:
webassembly/
- package:
file:///tmp/local-registry/acme/trustmee-verifier-components- local backend root:
/tmp/local-registry - package:
acme:trustmee-verifier-components
- local backend root:
oci://docker.io/acme/tdx-verifier-component- package:
acme:tdx-verifier-component - hash-form version:
0.0.0-component.sha0123... - locator-form latest version: highest non-yanked semver published for
acme:tdx-verifier-component
- package:
oci://docker.io/acme/tdx-verifier-component:1.2.3- package:
acme:tdx-verifier-component - locator-form pinned version:
1.2.3
- package:
For public or shared verifier components, use GitHub Container Registry (ghcr.io):
- it is a standard OCI registry
- public packages can be pulled anonymously
wasm-pkg-toolsalready documents GHCR-backed Wasm package layouts- it fits the package mapping above without introducing TrustMee-specific registry requirements
For private internal deployments, use either private GHCR or a self-hosted OCI registry such as Harbor. The TrustMee client-side mapping stays the same.
Docker Hub also works as an OCI registry. Use oci://docker.io/<dockerhub-user>/<package> as the TrustMee repository base or locator, and publish with the same Wasm package coordinates: <dockerhub-user>:<package>.
- Choose a base such as
oci://ghcr.io/<github-owner>/trustmee-verifier-componentsoroci://docker.io/<dockerhub-user>/tdx-verifier-component. - Build the Wasm component and compute its TrustMee
component_id. - Publish it using one of the two supported lookup styles:
- Hash form: convert the digest to package version
0.0.0-component.sha<sha256>. - Locator form: publish a normal semver package version such as
1.2.3. TrustMee can fetch that exact version with:1.2.3, or the latest non-yanked semver when no version is present in the locator URL.
- Hash form: convert the digest to package version
The simplest flow uses wkg from wasm-pkg-tools.
Example config at ~/.config/wasm-pkg/config.toml for GHCR:
[registry."ghcr.io"]
type = "oci"
[registry."ghcr.io".oci]
auth = { username = "<github-username>", password = "<github-pat-with-write:packages>" }Example config for Docker Hub:
[registry."docker.io"]
type = "oci"
[registry."docker.io".oci]
auth = { username = "<dockerhub-username>", password = "<dockerhub-token-or-password>" }Publish the component under the deterministic version derived from its SHA-256:
sha256="$(sha256sum ./path/to/verifier_component.wasm | awk '{print $1}')"
wkg publish ./path/to/verifier_component.wasm \
--package <github-owner>:trustmee-verifier-components@0.0.0-component.sha${sha256} \
--registry ghcr.ioDocker Hub example:
sha256="$(sha256sum ./path/to/tdx_verifier_component.wasm | awk '{print $1}')"
wkg publish ./path/to/tdx_verifier_component.wasm \
--package <dockerhub-user>:tdx-verifier-component@0.0.0-component.sha${sha256} \
--registry docker.ioThen the CMW EAT uses the hash-form component_id:
{
"component_id": "component-<sha256>"
}Run the verifier with the matching repository base so TrustMee can map that
hash to 0.0.0-component.sha<sha256> and fetch it:
cargo run -p wasm-verification-component -- \
--input input.cmw.json \
--component-repository-hint oci://docker.io/<dockerhub-user>/tdx-verifier-componentTrustMee rejects the fetched artifact if its bytes do not hash to the
component_id.
Publish the component under a normal semver version:
wkg publish ./path/to/tdx_verifier_component.signed.wasm \
--package <dockerhub-user>:tdx-verifier-component-signed@1.2.3 \
--registry docker.ioThen put the OCI locator directly in the CMW EAT component_id:
{
"component_id": "oci://docker.io/<dockerhub-user>/tdx-verifier-component-signed"
}With no :<semver> suffix, TrustMee probes Docker Hub and fetches the latest
non-yanked semver version. To pin a specific release instead, include the
version:
{
"component_id": "oci://docker.io/<dockerhub-user>/tdx-verifier-component-signed:1.2.3"
}Locator mode does not compare fetched bytes to a hash in the input. For mutable
"latest" deployments, use a --component-trust-store that pins trusted signer
keys, or make sure your policy accepts the resolved verifier_component_sha256
claim. The locator suffix is a Wasm package semver, not Docker's :latest tag.
Stapled application/wasm endorsements are not allowed with locator-form IDs.
Notes:
- For private GHCR packages, readers need
read:packages. - In GitHub Actions, you can usually publish with
GITHUB_TOKENwhen the package is associated with the workflow repository. - If you publish programmatically, use
wasm_pkg_client::Client::publish_release_dataorpublish_release_filewith the same package/version mapping shown above.
JSON CMW records are encoded as:
{
"__cmwc_t": "https://trustmee.invalid/cmw/verification-input",
"evidence": [
"application/eat-ucs+json; eat_profile=\"https://trustmee.invalid/eat/component-evidence\"",
"<base64url(EAT JSON payload)>",
4
],
"verifier": [
"application/wasm",
"<base64url(wasm bytes)>",
2
],
"snp-collateral": [
"application/vnd.trustmee.snp-collateral+cbor",
"<base64url(CBOR collateral)>",
2
]
}The inner JSON EAT payload uses:
{
"eat_profile": "https://trustmee.invalid/eat/component-evidence",
"component_id": "component-<sha256-of-wasm-bytes>",
"evidence_type": "application/octet-stream",
"evidence": "<base64url(raw evidence bytes)>"
}CBOR CMW input is accepted too. The integration tests cover both JSON and CBOR variants.
The test_data/ directory includes sample verification components and evidence files for local testing:
test_data/tdx_verifier_component.wasmtest_data/snp_verifier_component.wasmtest_data/snp_verifier_host_crypto_component.wasmtest_data/tdx_quote.bintest_data/snp_evidence.json
Signed sample assets are available under test_data/signature-demo/:
test_data/signature-demo/snp_verifier_component.private.pemtest_data/signature-demo/snp_verifier_component.public.pemtest_data/signature-demo/snp_verifier_component.trust-store.jsontest_data/signature-demo/snp_verifier_component.signed.wasm
These files are for local testing only.
Run the ready-made manual test script:
./scripts/test_snp_signature_manual.shThe script checks:
- unsigned SNP component without a trust store succeeds
- signed SNP component with the sample trust store succeeds
- signed SNP component with an expired trust store fails
- signed SNP component without a trust store still succeeds in direct mode for compatibility
cargo test -p wasm-verification-component --test sample_library_usage -- --nocapture
cargo test -p wasm-verification-component --test cmw_input -- --nocapture