Gunnar

nordisk/heimdall

guests/verify-bundle/tests/good_bundles.rs

// SPDX-License-Identifier: AGPL-3.0-only
//! Real bundles, produced by Holger's own library, are ACCEPTED, and the guest
//! says the same thing about them that Holger's own verifier says.

mod common;
use common::*;

use heimdall_guest_verify_bundle::{REPORT_NAME, REPORT_SCHEMA};

fn report(o: &Outcome) -> serde_json::Value {
    assert!(o.is_accepted(), "refused: {:?}", o.reason());
    serde_json::from_slice(&o.output).unwrap()
}

#[test]
fn a_pinned_signer_bundle_made_by_holger_is_accepted() {
    let fx = good();
    let o = fx.guest();
    let r = report(&o);
    assert_eq!(r["schema"], REPORT_SCHEMA);
    assert_eq!(r["bundle_id"], "bundle-0005");
    assert_eq!(r["sequence"], 5);
    assert_eq!(r["candidate_digest"], fx.candidate_digest);
    assert_eq!(r["release_signer_fingerprint"], fx.release.fingerprint);
    assert_eq!(r["approvals"].as_array().unwrap().len(), 2);
}

#[test]
fn a_rooted_chain_bundle_made_by_holger_is_accepted() {
    let fx = build(Spec {
        rooted: true,
        ..Spec::default()
    });
    let r = report(&fx.guest());
    assert!(r["checks"]
        .as_array()
        .unwrap()
        .iter()
        .any(|c| c.as_str().unwrap().contains("RootedChain")));
}

#[test]
fn the_guest_and_holgers_own_verifier_agree_on_every_reported_field() {
    let fx = good();
    let archive = fx.pack();
    let h = fx.holger(&archive).expect("Holger accepts its own bundle");
    let o = verify_bundle(&archive, &fx.params());
    let r = report(&o);
    assert_eq!(r["bundle_id"], h.bundle_id);
    assert_eq!(r["sequence"], h.sequence);
    assert_eq!(r["supplier"], h.supplier);
    assert_eq!(r["product"], h.product);
    assert_eq!(r["release_version"], h.release_version);
    assert_eq!(r["candidate_digest"], h.candidate_digest);
    assert_eq!(
        r["release_signer_fingerprint"],
        h.release_signer_fingerprint
    );
    assert_eq!(r["release_signer_subject"], h.release_signer_subject);
    assert_eq!(r["non_production_evidence"], h.non_production_evidence);
    let mut ga: Vec<(String, String, String)> = r["approvals"]
        .as_array()
        .unwrap()
        .iter()
        .map(|a| {
            (
                a["role"].as_str().unwrap().into(),
                a["fingerprint"].as_str().unwrap().into(),
                a["subject"].as_str().unwrap().into(),
            )
        })
        .collect();
    let mut ha: Vec<(String, String, String)> = h
        .approvals
        .iter()
        .map(|a| (a.role.clone(), a.fingerprint.clone(), a.subject.clone()))
        .collect();
    ga.sort();
    ha.sort();
    assert_eq!(ga, ha);
}

#[test]
fn an_accepted_bundle_emits_the_report_and_exactly_its_payload_and_evidence_bytes() {
    let fx = good();
    let o = fx.guest();
    assert!(o.is_accepted());
    let names: Vec<&str> = o.emitted.iter().map(|e| e.name.as_str()).collect();
    assert_eq!(
        names,
        vec![
            REPORT_NAME,
            "evidence+2fsbom+2fapp.cdx.json",
            "evidence+2fsource-receipt.json",
            "payload+2ffirmware.bin"
        ]
    );
    for e in &o.emitted[1..] {
        assert_eq!(
            &e.bytes,
            member_for(&fx.members, &e.name),
            "{} differs",
            e.name
        );
    }
    assert_eq!(
        o.emitted[0].bytes, o.output,
        "the report output and the emitted report are one"
    );
}

#[test]
fn emit_all_also_emits_the_control_members_and_emit_report_emits_only_the_report() {
    let fx = good();
    let all = verify_bundle(&fx.pack(), &fx.params_with("emit: All"));
    assert_eq!(all.emitted.len(), 1 + fx.members.len());
    let only = verify_bundle(&fx.pack(), &fx.params_with("emit: Report"));
    assert_eq!(only.emitted.len(), 1);
    assert_eq!(only.emitted[0].name, REPORT_NAME);
}

#[test]
fn a_multi_megabyte_payload_split_into_many_chunks_is_accepted_byte_exact() {
    let big: Vec<u8> = (0..9 * 1024 * 1024u32)
        .map(|i| (i.wrapping_mul(2654435761) >> 13) as u8)
        .collect();
    let mut spec = Spec::default();
    spec.payloads.push((
        "big/blob.bin".into(),
        big.clone(),
        "application/octet-stream".into(),
    ));
    let fx = build(spec);
    let o = fx.guest();
    assert!(o.is_accepted(), "{:?}", o.reason());
    let e = o
        .emitted
        .iter()
        .find(|e| e.name == "payload+2fbig+2fblob.bin")
        .unwrap();
    assert_eq!(e.bytes, big);
}

#[test]
fn an_empty_payload_file_is_accepted() {
    let mut spec = Spec::default();
    spec.payloads.push((
        "empty.bin".into(),
        Vec::new(),
        "application/octet-stream".into(),
    ));
    let o = build(spec).guest();
    assert!(o.is_accepted(), "{:?}", o.reason());
    assert!(o
        .emitted
        .iter()
        .any(|e| e.name == "payload+2fempty.bin" && e.bytes.is_empty()));
}

#[test]
fn a_bundle_with_no_expiry_is_accepted_when_the_policy_does_not_require_one() {
    let o = build(Spec {
        expires_in: None,
        ..Spec::default()
    })
    .guest();
    assert!(o.is_accepted(), "{:?}", o.reason());
}

#[test]
fn many_small_members_are_accepted() {
    let mut spec = Spec::default();
    for i in 0..300 {
        spec.payloads.push((
            format!("pkgs/p{i:04}.bin"),
            format!("pkg {i}").into_bytes(),
            "application/octet-stream".into(),
        ));
    }
    let o = build(spec).guest();
    assert!(o.is_accepted(), "{:?}", o.reason());
    assert_eq!(o.emitted.len(), 1 + 301 + 2);
}

#[test]
fn verification_is_deterministic_byte_for_byte() {
    let fx = good();
    let a = fx.pack();
    let p = fx.params();
    let first = verify_bundle(&a, &p);
    for _ in 0..3 {
        assert_eq!(verify_bundle(&a, &p), first);
    }
}

#[test]
fn a_bundle_holger_packs_itself_with_openzl_members_is_accepted_like_holger_accepts_it() {
    // Was the open finding (heimdall-bundle-3): znippy compresses with OpenZL.
    // With the `openzl` feature the guest decodes the frames itself; without
    // it the same file is still refused by name.
    let fx = good();
    let archive = pack_holger(&fx.members);
    let h = fx
        .holger(&archive)
        .expect("Holger reads its own OpenZL archive");
    let o = verify_bundle(&archive, &fx.params());
    if cfg!(feature = "openzl") {
        let r = report(&o);
        assert_eq!(r["bundle_id"], h.bundle_id);
        assert_eq!(r["candidate_digest"], h.candidate_digest);
        assert_eq!(
            r["release_signer_fingerprint"],
            h.release_signer_fingerprint
        );
    } else {
        assert_refused(&o, "heimdall-bundle-3", "OpenZL");
    }
}

#[test]
fn every_output_name_is_one_plain_file_name_and_the_mapping_is_injective() {
    let paths = [
        "payload/firmware.bin",
        "payload+2ffirmware.bin",
        "payload/a+b",
        ".hidden",
        "verify-report.json",
        "evidence/sbom/app.cdx.json",
        "payload/ünïcode",
    ];
    let mut seen = std::collections::BTreeSet::new();
    for p in paths {
        let n = output_name(p);
        assert!(!n.is_empty() && n.len() <= 255, "{n}");
        assert!(!n.starts_with('.'), "{n}");
        assert!(
            n.chars()
                .all(|c| c.is_ascii_alphanumeric() || "._-+".contains(c)),
            "{n}"
        );
        assert_ne!(n, REPORT_NAME);
        assert!(seen.insert(n.clone()), "{p} collides as {n}");
    }
    assert_eq!(
        output_name("payload/firmware.bin"),
        "payload+2ffirmware.bin"
    );
    let long = format!("payload/{}", "x".repeat(300));
    assert!(output_name(&long).starts_with("member+"));
}