Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

jobs/runner/tests/vendored_heimdall_guests.rs

//! **Heimdall's released verify-bundle guests, vendored** (lane HOL-HEIMDALL-02): the ten files
//! of heimdall-guests-0.2.1 under `guests/heimdall/0.2.1/` are the ones the release names.
//!
//! * every module matches its pin in `PINS.toml` AND Holger's compiled-in pin
//!   (`guests::RELEASE`), by sha256 and BLAKE3, and its `.wasm.blake3` sidecar says the same;
//! * the release's SLSA statement (DSSE, the owner's YubiKey: Holger's own
//!   `slsa/release-signing-key.pub`, dwarves' release runner) names each module's sha256,
//!   verified by Holger's own provenance verifier;
//! * each `.wasm.p7s` verifies against the korp root, inside Heimdall's host, as the split pair
//!   Holger runs (the decoder first) and the single-instance guest load;
//! * a module that is not the pinned one, or a trust root that is not the korp root, is refused.

use std::path::{Path, PathBuf};

use holger_job_runner::guests::{check_files, load_split, Pin, DIR, RELEASE};

fn repo() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR")).join("../..")
}

fn dir() -> PathBuf {
    let d = repo().join(DIR);
    let probe = std::fs::read(d.join(RELEASE.verifier.file)).unwrap();
    assert!(
        !probe.starts_with(b"version https://git-lfs"),
        "{} is an LFS pointer: run `git lfs pull` first",
        RELEASE.verifier.file
    );
    d
}

/// The korp root as DER in `tmp` (Heimdall's host takes DER roots).
fn korp_root(tmp: &Path) -> PathBuf {
    let pem = std::fs::read_to_string(repo().join("holger-recipe/trust/korp-root-ca.pem")).unwrap();
    der_file(&pem, tmp, "korp-root-ca.der")
}

fn der_file(pem: &str, tmp: &Path, name: &str) -> PathBuf {
    use base64::Engine as _;
    let b64: String = pem.lines().filter(|l| !l.starts_with("-----")).collect();
    let der = base64::engine::general_purpose::STANDARD
        .decode(b64.trim())
        .unwrap();
    let p = tmp.join(name);
    std::fs::write(&p, der).unwrap();
    p
}

#[test]
fn every_vendored_file_is_the_pinned_one_and_pins_toml_says_the_compiled_pins() {
    let d = dir();
    let pins: toml::Table = std::fs::read_to_string(d.join("PINS.toml"))
        .unwrap()
        .parse()
        .unwrap();
    assert_eq!(pins["release"].as_str(), Some(RELEASE.release));
    assert_eq!(pins["tag"].as_str(), Some(RELEASE.tag));
    assert_eq!(pins["commit"].as_str(), Some(RELEASE.commit));
    assert_eq!(pins["attestation"].as_str(), Some(RELEASE.attestation));
    let listed = pins["guest"].as_array().unwrap();
    assert_eq!(listed.len(), 3);
    for pin in RELEASE.pins() {
        let row = listed
            .iter()
            .find(|g| g["role"].as_str() == Some(pin.role))
            .unwrap_or_else(|| panic!("{} in PINS.toml", pin.role));
        assert_eq!(row["file"].as_str(), Some(pin.file));
        assert_eq!(row["sha256"].as_str(), Some(pin.sha256), "{}", pin.file);
        assert_eq!(row["blake3"].as_str(), Some(pin.blake3), "{}", pin.file);
        check_files(&d, &pin).unwrap();
        assert!(
            d.join(format!("{}.p7s", pin.file)).is_file(),
            "{}.p7s",
            pin.file
        );
    }
    // The ten release files and the pins file, nothing else.
    let mut names: Vec<String> = std::fs::read_dir(&d)
        .unwrap()
        .flatten()
        .map(|e| e.file_name().to_string_lossy().into_owned())
        .collect();
    names.sort();
    assert_eq!(names.len(), 11, "{names:?}");
    // A changed module is refused by name.
    let tmp = tempfile::tempdir().unwrap();
    for f in std::fs::read_dir(&d).unwrap().flatten() {
        std::fs::copy(f.path(), tmp.path().join(f.file_name())).unwrap();
    }
    let p = tmp.path().join(RELEASE.decoder.file);
    let mut b = std::fs::read(&p).unwrap();
    let n = b.len() / 2;
    b[n] ^= 1;
    std::fs::write(&p, b).unwrap();
    let e = check_files(tmp.path(), &RELEASE.decoder).unwrap_err();
    assert!(
        e.contains("sha256") && e.contains(RELEASE.decoder.sha256),
        "{e}"
    );
}

#[test]
fn the_releases_slsa_statement_signed_with_the_owners_key_names_every_module() {
    use holger_provenance::{effective, verify_artifact, ProvenanceFloor, ProvenanceGate, Verdict};
    const BUILDER: &str = "https://git.gunnar.rs/nordisk/dwarves/slsa/builders/dwarves-server/v1";
    const KEYID: &str = "d24d3785e8281bcd37e8f2c40a3a85e8152d3ce2200a5c929a1a5ca636e8249e";
    let d = dir();
    let pem = std::fs::read_to_string(repo().join("slsa/release-signing-key.pub")).unwrap();
    let floor: ProvenanceFloor = ron::from_str(&format!(
        r#"(keys: [(id: "{KEYID}", alg: ecdsa_p256, public_key: "{}")])"#,
        pem.replace('\n', "\\n")
    ))
    .unwrap();
    let gate: ProvenanceGate = ron::from_str(&format!(
        r#"require(builders: [(id: "{BUILDER}", level: 3)], keys: ["{KEYID}"], slsa_min: 3)"#
    ))
    .unwrap();
    let policy = effective(&floor, &gate);
    let att = vec![(
        RELEASE.attestation.to_string(),
        std::fs::read(d.join(RELEASE.attestation)).unwrap(),
    )];
    for pin in RELEASE.pins() {
        let r = verify_artifact(
            &std::fs::read(d.join(pin.file)).unwrap(),
            &att,
            &policy,
            None,
        );
        assert_eq!(r.verdict, Verdict::Pass, "{}: {}", pin.file, r.detail);
        let c = r
            .verified_provenance()
            .next()
            .expect("a verified statement");
        assert_eq!(c.builder_id.as_deref(), Some(BUILDER));
        let slsa = c.slsa.as_ref().unwrap();
        assert_eq!(slsa.external_parameters["release"], RELEASE.release);
    }
    // Not a byte of another module passes.
    let r = verify_artifact(b"not a guest", &att, &policy, None);
    assert_ne!(r.verdict, Verdict::Pass);
}

#[test]
fn the_split_pair_loads_signed_under_the_korp_root_with_holgers_pins_and_nothing_else_does() {
    let d = dir();
    let tmp = tempfile::tempdir().unwrap();
    let root = korp_root(tmp.path());
    let limits = heimdall_run::RunLimits::default();
    let g = load_split(&d, &RELEASE, std::slice::from_ref(&root), &limits).unwrap();
    assert_eq!(g.digest_hex(), RELEASE.verifier.blake3);
    assert_eq!(g.decoder_digest_hex(), Some(RELEASE.decoder.blake3));
    assert!(g.signer().contains("plugin signing"), "{}", g.signer());
    let single = heimdall_run::wasm::load_guest(
        &d.join(RELEASE.single.file),
        std::slice::from_ref(&root),
        Some(RELEASE.single.blake3),
        &limits,
    )
    .unwrap();
    assert_eq!(single.digest_hex(), RELEASE.single.blake3);

    // Another pin: refused before anything runs.
    let wrong = holger_job_runner::guests::Release {
        decoder: Pin {
            blake3: RELEASE.single.blake3,
            ..RELEASE.decoder
        },
        ..RELEASE
    };
    assert!(load_split(&d, &wrong, &[root], &limits).is_err());
    // Another trust root (Holger's release key's certificate is no plugin root): refused.
    let other = der_file(
        &std::fs::read_to_string(repo().join("slsa/yubikey-piv-attestation-ca.pem")).unwrap(),
        tmp.path(),
        "other.der",
    );
    let e = load_split(&d, &RELEASE, &[other], &limits)
        .err()
        .expect("refused");
    assert!(e.contains(RELEASE.release), "{e}");
    // No trust root at all: there is no unsigned mode.
    assert!(load_split(&d, &RELEASE, &[], &limits).is_err());
}

/// Lane HOL-HEIMDALL-04: the korp root the box stages as PEM is the DER a job carries, and a
/// DER file stays as it is.
#[test]
fn the_trust_root_pem_is_read_as_its_der() {
    let tmp = tempfile::tempdir().unwrap();
    let want = std::fs::read(korp_root(tmp.path())).unwrap();
    let pem = std::fs::read(repo().join("holger-recipe/trust/korp-root-ca.pem")).unwrap();
    assert_eq!(holger_job_runner::guests::der_of(&pem).unwrap(), want);
    assert_eq!(holger_job_runner::guests::der_of(&want).unwrap(), want);
    holger_job_runner::guests::check_release(&dir(), &RELEASE).unwrap();
}