a3s-box-runtime 3.2.2

MicroVM runtime engine — VM lifecycle, OCI images, attestation, networking
Documentation
use std::path::Path;

use a3s_runtime::contract::{
    ArtifactRef, IsolationLevel, RuntimeInspection, RuntimeObservation, RuntimeUnitSpec,
    RuntimeUnitState,
};
use a3s_runtime::RuntimeClient;
use serde::Deserialize;
use sha2::{Digest, Sha256};

use crate::tee::attestation::SNP_REPORT_SIZE;
use crate::tee::{
    is_simulated_report, parse_platform_info, verify_attestation, AttestationPolicy,
    AttestationReport,
};

use super::super::attestation::{attestation_path, ATTESTATION_MEDIA_TYPE};
use super::fixture::BoxRuntimeConformanceFixture;
use super::{require, Result};

const ATTESTATION_SCHEMA: &str = "a3s.box.runtime.attestation.v1";
const SEMANTICS_PROFILE_DIGEST: &str =
    "sha256:8d65d845f5e5523e34fe91ffbebc35315bc814a2c48b76da1f4e82f20e09f78d";
const IDENTITY_ATTACHMENT_DIGEST: &str =
    "sha256:8a29be89b1fa2103fe694ec9588705774bf279c4651bc0891977f84a7a3d05c1";
const REPORT_DATA_OFFSET: usize = 0x50;
const REPORT_DATA_SIZE: usize = 64;
const RUNTIME_BINDING_OFFSET: usize = REPORT_DATA_OFFSET + 32;
const RUNTIME_BINDING_SIZE: usize = 32;

#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct StoredAttestation {
    schema: String,
    unit_id: String,
    runtime_generation: u64,
    spec_digest: String,
    provider_resource_id: String,
    execution_generation: u64,
    mode: String,
    policy: AttestationPolicy,
    ratls_certificate: Vec<u8>,
    report: AttestationReport,
}

pub(super) async fn run(
    fixture: &BoxRuntimeConformanceFixture,
    client: &dyn RuntimeClient,
) -> Result<()> {
    let config = fixture.sev_snp_config().ok_or_else(|| {
        super::protocol("Evidence profile requires explicit SEV-SNP configuration")
    })?;

    let mut task_request = fixture.cases.task(
        "evidence-confidential-task",
        "printf 'r17-confidential-task-attested\\n'",
        10_000,
    );
    task_request.spec.isolation = IsolationLevel::Confidential;
    task_request.spec.semantics_profile_digest = Some(SEMANTICS_PROFILE_DIGEST.into());
    task_request.spec.identity_attachment_digest = Some(IDENTITY_ATTACHMENT_DIGEST.into());

    let succeeded = client.apply(&task_request).await?;
    let task_attestation = verify_observation(
        &succeeded,
        &task_request.spec,
        config.simulate,
        RuntimeUnitState::Succeeded,
    )?;
    let task_provider_id = succeeded
        .provider_resource_id
        .as_deref()
        .ok_or_else(|| super::protocol("confidential Task omitted provider identity"))?;
    let task_record = fixture.record_for(&task_request.spec).await?;
    let task_metadata = task_record
        .managed_execution
        .as_ref()
        .ok_or_else(|| super::protocol("confidential Task lost managed metadata"))?;
    require(
        task_metadata.request.config.deferred_main,
        "confidential Task was not protected by the attestation-before-execution gate",
    )?;
    let task_generation = task_metadata.generation;
    let task_path = attestation_path(&task_record, task_generation);
    let task_bytes = std::fs::read(&task_path)
        .map_err(|error| super::external("read confidential Task attestation", error))?;
    verify_artifact(
        &task_path,
        &task_bytes,
        &task_attestation,
        &task_request.spec,
        task_provider_id,
        task_generation.get(),
        config,
    )?;
    fixture
        .remove_unit(client, &task_request.spec, "evidence-confidential-task")
        .await?;
    require(
        !task_path.exists(),
        "confidential Task removal retained its execution attestation artifact",
    )?;

    let mut request = fixture.cases.service(
        "evidence-confidential-service",
        "printf 'r17-confidential-ready\\n'; exec sleep 3600",
    );
    request.spec.isolation = IsolationLevel::Confidential;
    request.spec.semantics_profile_digest = Some(SEMANTICS_PROFILE_DIGEST.into());
    request.spec.identity_attachment_digest = Some(IDENTITY_ATTACHMENT_DIGEST.into());

    let running = client.apply(&request).await?;
    let first_attestation = verify_observation(
        &running,
        &request.spec,
        config.simulate,
        RuntimeUnitState::Running,
    )?;
    let first_provider_id = running
        .provider_resource_id
        .as_deref()
        .ok_or_else(|| super::protocol("confidential observation omitted provider identity"))?;

    let record = fixture.record_for(&request.spec).await?;
    let execution_generation = record
        .managed_execution
        .as_ref()
        .ok_or_else(|| super::protocol("confidential execution lost managed metadata"))?
        .generation;
    let path = attestation_path(&record, execution_generation);
    let bytes = std::fs::read(&path)
        .map_err(|error| super::external("read persisted SEV-SNP attestation", error))?;
    verify_artifact(
        &path,
        &bytes,
        &first_attestation,
        &request.spec,
        first_provider_id,
        execution_generation.get(),
        config,
    )?;

    let inspected = found(client.inspect(&request.spec.unit_id).await?)?;
    let inspected_attestation = verify_observation(
        &inspected,
        &request.spec,
        config.simulate,
        RuntimeUnitState::Running,
    )?;
    require(
        inspected.provider_resource_id == running.provider_resource_id
            && inspected_attestation == first_attestation,
        "live reinspection changed identity or attestation within one execution generation",
    )?;

    let restarted_driver = fixture.restarted_driver()?;
    let restarted = fixture.client_with(restarted_driver, fixture.state.clone());
    let recovered = found(restarted.inspect(&request.spec.unit_id).await?)?;
    let recovered_attestation = verify_observation(
        &recovered,
        &request.spec,
        config.simulate,
        RuntimeUnitState::Running,
    )?;
    require(
        recovered.provider_resource_id == running.provider_resource_id
            && recovered_attestation == first_attestation,
        "driver reconstruction did not preserve and live-verify the exact attestation",
    )?;

    let mut tampered: serde_json::Value = serde_json::from_slice(&bytes)
        .map_err(|error| super::external("decode attestation tamper fixture", error))?;
    tampered["spec_digest"] = serde_json::Value::String(format!("sha256:{}", "0".repeat(64)));
    let tampered = serde_json::to_vec(&tampered)
        .map_err(|error| super::external("encode attestation tamper fixture", error))?;
    std::fs::write(&path, tampered)
        .map_err(|error| super::external("write attestation tamper fixture", error))?;
    let rejected = restarted.inspect(&request.spec.unit_id).await;
    std::fs::write(&path, &bytes)
        .map_err(|error| super::external("restore attestation after tamper fixture", error))?;
    require(
        rejected.is_err(),
        "Runtime inspection accepted a tampered persisted attestation",
    )?;
    let restored = found(restarted.inspect(&request.spec.unit_id).await?)?;
    require(
        verify_observation(
            &restored,
            &request.spec,
            config.simulate,
            RuntimeUnitState::Running,
        )? == first_attestation,
        "restored attestation did not recover the exact live evidence",
    )?;

    fixture
        .remove_unit(&restarted, &request.spec, "evidence-confidential-service")
        .await?;
    require(
        !path.exists(),
        "confidential removal retained the execution attestation artifact",
    )
}

fn found(inspection: RuntimeInspection) -> Result<RuntimeObservation> {
    match inspection {
        RuntimeInspection::Found { observation, .. } => Ok(*observation),
        RuntimeInspection::NotFound { .. } => Err(super::protocol(
            "confidential Service disappeared during Evidence certification",
        )),
    }
}

fn verify_observation(
    observation: &RuntimeObservation,
    spec: &RuntimeUnitSpec,
    simulated: bool,
    expected_state: RuntimeUnitState,
) -> Result<ArtifactRef> {
    observation
        .validate_against(spec)
        .map_err(super::protocol)?;
    require(
        observation.state == expected_state,
        format!(
            "Evidence fixture expected confidential unit state {expected_state:?}, observed {:?}",
            observation.state
        ),
    )?;
    let evidence = observation
        .evidence
        .as_ref()
        .ok_or_else(|| super::protocol("confidential observation omitted Runtime evidence"))?;
    require(
        evidence.spec_digest == spec.digest().map_err(super::protocol)?
            && evidence.semantics_profile_digest == spec.semantics_profile_digest
            && evidence.identity_attachment_digest == spec.identity_attachment_digest
            && observation.provider_build.as_ref() == Some(&evidence.provider_build),
        "Runtime evidence did not bind the exact spec, semantics profile, identity attachment, and provider build",
    )?;
    require(
        evidence
            .claims
            .get("a3s.box.execution-isolation")
            .map(String::as_str)
            == Some("microvm"),
        "confidential Runtime evidence did not identify MicroVM isolation",
    )?;
    let expected_mode = if simulated {
        "sev-snp-simulated"
    } else {
        "sev-snp-hardware"
    };
    require(
        evidence.claims.get("a3s.box.tee").map(String::as_str) == Some(expected_mode)
            && evidence
                .provider_build
                .contains(&format!("tee/{expected_mode}")),
        "confidential Runtime evidence reported the wrong TEE mode",
    )?;
    require(
        evidence
            .claims
            .get("a3s.box.execution-generation")
            .and_then(|value| value.parse::<u64>().ok())
            .is_some_and(|value| value > 0),
        "confidential Runtime evidence omitted a valid execution generation",
    )?;
    observation
        .provider_attestation
        .clone()
        .ok_or_else(|| super::protocol("confidential observation omitted provider attestation"))
}

#[allow(clippy::too_many_arguments)]
fn verify_artifact(
    path: &Path,
    bytes: &[u8],
    reference: &ArtifactRef,
    spec: &RuntimeUnitSpec,
    provider_resource_id: &str,
    execution_generation: u64,
    config: &super::super::BoxRuntimeSevSnpConfig,
) -> Result<()> {
    verify_private_regular_file(path)?;
    let digest = format!("sha256:{:x}", Sha256::digest(bytes));
    require(
        reference.digest == digest
            && reference.media_type == ATTESTATION_MEDIA_TYPE
            && reference.uri
                == format!(
                    "a3s-box-attestation://{provider_resource_id}/executions/{execution_generation}/{}",
                    digest.trim_start_matches("sha256:")
                ),
        "attestation Artifact reference did not bind its exact immutable bytes and execution",
    )?;

    let stored: StoredAttestation = serde_json::from_slice(bytes)
        .map_err(|error| super::external("decode persisted SEV-SNP attestation", error))?;
    let expected_mode = if config.simulate {
        "sev-snp-simulated"
    } else {
        "sev-snp-hardware"
    };
    require(
        stored.schema == ATTESTATION_SCHEMA
            && stored.unit_id == spec.unit_id
            && stored.runtime_generation == spec.generation
            && stored.spec_digest == spec.digest().map_err(super::protocol)?
            && stored.provider_resource_id == provider_resource_id
            && stored.execution_generation == execution_generation
            && stored.mode == expected_mode
            && stored.policy == config.attestation_policy,
        "persisted attestation did not bind the Runtime and Box execution identity or policy",
    )?;
    require(
        stored.report.report.len() == SNP_REPORT_SIZE
            && is_simulated_report(&stored.report.report) == config.simulate
            && parse_platform_info(&stored.report.report).as_ref() == Some(&stored.report.platform),
        "persisted attestation report mode or platform metadata was invalid",
    )?;

    let spec_digest = spec.digest().map_err(super::protocol)?;
    let expected_binding = hex::decode(
        spec_digest
            .strip_prefix("sha256:")
            .ok_or_else(|| super::protocol("Runtime spec digest was not SHA-256"))?,
    )
    .map_err(|error| super::external("decode Runtime spec binding", error))?;
    require(
        stored.report.report[RUNTIME_BINDING_OFFSET..RUNTIME_BINDING_OFFSET + RUNTIME_BINDING_SIZE]
            == expected_binding,
        "SEV-SNP report_data did not bind the exact Runtime specification",
    )?;
    let report_data =
        &stored.report.report[REPORT_DATA_OFFSET..REPORT_DATA_OFFSET + REPORT_DATA_SIZE];
    let verification = verify_attestation(
        &stored.report,
        report_data,
        &config.attestation_policy,
        config.simulate,
    )
    .map_err(|error| super::external("verify persisted SEV-SNP report", error))?;
    require(
        verification.verified,
        format!(
            "persisted SEV-SNP report failed policy verification: {}",
            verification.failures.join("; ")
        ),
    )?;
    require(
        !stored.ratls_certificate.is_empty(),
        "real-provider Evidence certification requires the live RA-TLS certificate",
    )?;
    let embedded = crate::tee::ratls::extract_report_from_cert(&stored.ratls_certificate)
        .map_err(|error| super::external("extract report from RA-TLS certificate", error))?;
    require(
        embedded == stored.report
            && crate::tee::ratls::verify_pubkey_binding(
                &stored.ratls_certificate,
                &stored.report.report,
            )
            .map_err(|error| super::external("verify RA-TLS public-key binding", error))?,
        "RA-TLS certificate did not contain and key-bind the persisted report",
    )
}

#[cfg(unix)]
fn verify_private_regular_file(path: &Path) -> Result<()> {
    use std::os::unix::fs::MetadataExt;

    let metadata = std::fs::symlink_metadata(path)
        .map_err(|error| super::external("inspect persisted attestation permissions", error))?;
    require(
        metadata.is_file()
            && !metadata.file_type().is_symlink()
            && metadata.uid() == unsafe { libc::geteuid() }
            && metadata.mode() & 0o077 == 0,
        "persisted attestation is not a private same-owner regular file",
    )
}

#[cfg(not(unix))]
fn verify_private_regular_file(path: &Path) -> Result<()> {
    let metadata = std::fs::symlink_metadata(path)
        .map_err(|error| super::external("inspect persisted attestation file", error))?;
    require(
        metadata.is_file() && !metadata.file_type().is_symlink(),
        "persisted attestation is not a regular file",
    )
}