Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Wrapping attestation surfaces

audience: ai

Every attestation level from provider-reads is produced the same way at the mosaik bond layer: the provider publishes evidence that another peer can verify before the bond forms. This chapter walks how each level is produced in practice, what the provider’s image does to ship it, and what the verifier re-checks.

Software — the null case

The provider’s attestation_digest is the blake3 digest of its long-term Ed25519 identity public key. The bond-formation handshake checks signatures produced by that key against the published digest. There is no hardware evidence; the Software level names that fact explicitly rather than pretending otherwise.

// Provider side.
let identity_sk = ed25519::SigningKey::from_bytes(&seed);
let identity_pk = identity_sk.verifying_key();
let attestation_digest = UniqueId::hash(identity_pk.as_bytes());

// Verifier side, inside the bond handshake.
let challenge = bond_challenge_bytes();
let sig = peer_sign(challenge);
assert!(identity_pk.verify(&challenge, &sig).is_ok());

Threat model: a key-leak compromises every signature the provider ever produced under that identity. A provider losing its key publishes a retirement marker; consumers downstream of the leaked provider’s signatures re-verify against a new identity.

TdxLocal — per-peer TDX quote

The provider runs inside a TDX guest whose Measurements are declared in the organism’s Config. At bond-formation, the provider generates a TDX quote binding the bond’s nonce and the peer’s identity into the quote’s report_data field.

// Inside the TDX guest, provider-side.
let report_data = blake3::Hasher::new()
    .update(b"signer-bond|")
    .update(peer_identity_pk.as_bytes())
    .update(&bond_nonce)
    .finalize();
let quote = mosaik::tee::tdx::generate_quote(&report_data);

// Peer verifies locally.
let quote = receive_quote_from_bond();
let td_info = mosaik::tee::tdx::parse_quote(&quote)?;
assert_eq!(td_info.mr_td, DECLARED_MR_TD);
assert_eq!(td_info.mr_config_id, DECLARED_MR_CONFIG_ID);
assert_eq!(
    td_info.report_data,
    expected_report_data(peer_identity_pk, &bond_nonce),
);

The verification is local — no round trip to Intel’s DCAP service. A peer verifying a TdxLocal quote re-computes the attestation check against Intel’s anchor certificates (shipped with the verifier image) and the organism’s declared Measurements.

Threat model: the TDX guest’s image is the trust anchor. An attacker with a zero-day against TDX defeats local verification; the TdxRemote level adds a DCAP round-trip that independent consumers rely on.

TdxRemote — DCAP-verified quote

Same generation path as TdxLocal. The verification path additionally routes the quote through Intel’s DCAP attestation service (or a declared equivalent):

let quote = receive_quote_from_bond();

// Local parse (same as TdxLocal).
let td_info = mosaik::tee::tdx::parse_quote(&quote)?;
assert_eq!(td_info.mr_td, DECLARED_MR_TD);

// Additional: DCAP round-trip.
let dcap = mosaik::tee::tdx::dcap::Client::new(
    DECLARED_DCAP_ROOT_URL,
);
let verdict = dcap.verify(&quote).await?;
assert!(matches!(verdict, dcap::Verdict::Ok));

A consumer outside the committee can re-verify an outcome’s aggregate by pulling the participating providers’ quotes from the organism’s stream of bond-time evidence and re-running the DCAP verification. This is the canonical production floor.

TdxRaTlsBidirectional — two-way attested channel

Both sides of the bond produce and verify quotes. Neither side accepts a non-attested counterpart; a committee member whose peer fails to produce a quote refuses to bond.

let server = mosaik::tee::tdx::ra_tls::server_config(
    DECLARED_MR_TD,
);
let client = mosaik::tee::tdx::ra_tls::client_config(
    DECLARED_MR_TD,
);

// Server side:
let (peer_quote, stream) = server.accept(tcp).await?;
let peer_td = parse_and_verify(&peer_quote)?;
assert_eq!(peer_td.mr_td, DECLARED_MR_TD);

// Client side:
let (peer_quote, stream) = client.connect(tcp, peer_spki).await?;
let peer_td = parse_and_verify(&peer_quote)?;
assert_eq!(peer_td.mr_td, DECLARED_MR_TD);

The bidirectional check matters at bond-formation. A downgrade attack — an adversary attempting to convince a matched-Measurements peer to accept a non-attested counterpart — surfaces as a connection refused at the RA-TLS handshake, not as a silently-accepted bond later caught by a second- line audit.

TdxPlusReproducibleBuild — source-to-binary anchor

The highest declared level. The provider additionally publishes:

  1. The build recipe — a declarative specification (Nix derivation, Bazel rule, Dockerfile checked-in under a pinned base image) that produces the binary whose Measurements the organism declared.
  2. A reproducible build artefact with a declared toolchain version. Anyone reproducing the build gets a binary with matching Measurements.

The consumer verifies:

// Offline verification by the consumer (or a third
// party auditing on the consumer's behalf).
let recipe = fetch(PROVIDER_RECIPE_URL).await?;
let recipe_digest = blake3::hash(&recipe);
assert_eq!(recipe_digest, DECLARED_RECIPE_DIGEST);

let build_output = rebuild_from_recipe(&recipe)?;
let mr_td = mosaik::tee::tdx::measurements_from_image(&build_output);
assert_eq!(mr_td, DECLARED_MR_TD);

This does not reduce trust to zero; the consumer still trusts the toolchain’s integrity and the declared anchor certificates. But the consumer no longer trusts the operator’s build pipeline — the binary the operator ships is the binary the source produces.

What the verifier never does

Across all levels above Software:

  • Never accept a quote whose Measurements do not match the declared set. A committee member that receives a non-matching quote treats the peer as absent, not as a fallback to a lower level.
  • Never ship the quote’s body into the public SignatureOutcome. The outcome carries a digest of the quote; the full quote is held by bonded peers and published to the organism’s evidence stream where consumers can pull it for audit.
  • Never re-use a quote across bonds. The bond nonce is fresh per bond; a replayed quote is an attack and rejected at the verifier.

Forward

Chapter 5 (signing) walks the request flow: how an admitted request enters the committee, how each provider produces a partial signature, and how partial sigs reach the committee-internal aggregator.