Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

TrustMee Verification Library

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.md
  • TRUSTMEE_OUTPUT_EAT_PROFILE.md
  • TRUSTMEE_CMW_COLLECTION_TYPE.md

Related projects

  • 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.

Input model

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_id
  • evidence
  • evidence_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

CLI usage

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> \
  --compact

Component trust store

When --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_key accepts PEM or OpenSSH text. Hex, base64, and base64url encodings of raw wasmsign2 key bytes are accepted too.
  • fuel = -1 means unlimited Wasmtime fuel. Any other value must be a non-negative integer.
  • valid_until must 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-signer tool to add --signature-expires-at before signing with wasmsign2.

Execution policy:

  • CMW verification is restrictive by default.
  • An unsigned component runs with 1_000_000_000 Wasmtime 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 fuel limit 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_bytes and verify_paths calls keep legacy behavior unless a trust store is explicitly supplied.
  • Result claim verifier_component_sha256 is 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_key carries the trusted public key used for that validation.
  • CMW component cache identity still uses the exact component_id digest from the input, including embedded signature and expiry metadata.

OCI package mapping

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 same component_id.
  • oci://...: locator form. The component_id is 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 version 0.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...
  • oci://ghcr.io/webassembly/acme/trustmee-verifier-components
    • package: acme:trustmee-verifier-components
    • namespace prefix: webassembly/
  • file:///tmp/local-registry/acme/trustmee-verifier-components
    • local backend root: /tmp/local-registry
    • package: acme:trustmee-verifier-components
  • 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
  • oci://docker.io/acme/tdx-verifier-component:1.2.3
    • package: acme:tdx-verifier-component
    • locator-form pinned version: 1.2.3

Recommended registry

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-tools already 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>.

Publishing components to an OCI registry

  1. Choose a base such as oci://ghcr.io/<github-owner>/trustmee-verifier-components or oci://docker.io/<dockerhub-user>/tdx-verifier-component.
  2. Build the Wasm component and compute its TrustMee component_id.
  3. 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.

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>" }

Option 1: hash-based publish and fetch

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.io

Docker 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.io

Then 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-component

TrustMee rejects the fetched artifact if its bytes do not hash to the component_id.

Option 2: locator-based publish and fetch latest

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.io

Then 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_TOKEN when the package is associated with the workflow repository.
  • If you publish programmatically, use wasm_pkg_client::Client::publish_release_data or publish_release_file with the same package/version mapping shown above.

TrustMee CMW shape

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.

Sample artifacts

The test_data/ directory includes sample verification components and evidence files for local testing:

  • test_data/tdx_verifier_component.wasm
  • test_data/snp_verifier_component.wasm
  • test_data/snp_verifier_host_crypto_component.wasm
  • test_data/tdx_quote.bin
  • test_data/snp_evidence.json

Signed sample assets are available under test_data/signature-demo/:

  • test_data/signature-demo/snp_verifier_component.private.pem
  • test_data/signature-demo/snp_verifier_component.public.pem
  • test_data/signature-demo/snp_verifier_component.trust-store.json
  • test_data/signature-demo/snp_verifier_component.signed.wasm

These files are for local testing only.

Manual SNP Signature Demo

Run the ready-made manual test script:

./scripts/test_snp_signature_manual.sh

The 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

Tests

cargo test -p wasm-verification-component --test sample_library_usage -- --nocapture
cargo test -p wasm-verification-component --test cmw_input -- --nocapture

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages