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

nordisk/holger

update-bundle/src/lib.rs

//! # holger-update-bundle — Secure Update Gateway bundle core
//!
//! A **network-free** library defining the signed `holger.update-bundle/v1` format,
//! its two-person approval + release-signature trust model, and a fully offline
//! verifier. It is reusable by the authoring CLI (`holger-bundle`), the standalone
//! verifier (`holger-verify`), the offline server import path, and backup/scrub
//! tooling. It has **no** server, UI, connector, or outbound-networking dependency
//! by construction (the zero-egress link-audit enforces this).
//!
//! ## Trust model
//!
//! * **Container.** A bundle is a znippy archive (no new binary format is invented)
//!   holding a fixed member layout: `manifest.json` (envelope), `core.json` (the
//!   immutable candidate), `payload/`, `evidence/`, `approvals/`, and `signatures/`.
//! * **Digests.** Every payload and evidence member carries a **SHA-256 and a
//!   BLAKE3** digest, recorded in `core.json` and again in the release manifest.
//! * **Candidate digest.** `core.json` is written once; `candidate_digest =
//!   sha256(core.json bytes)`. Every approval binds this digest.
//! * **Approvals.** Each approval is a **detached ed25519 signature over the exact
//!   approval-statement bytes**. The approver's role is authorized by the signer
//!   **certificate fingerprint** against the trust policy — never by the role
//!   string in the statement.
//! * **Two-person rule.** The policy requires a minimum number of *distinct*
//!   approver certificates and specific roles, each satisfied by a *distinct*
//!   certificate; one certificate cannot satisfy two required roles. The release
//!   signer must be distinct from the approvers.
//! * **Release manifest.** `signatures/release-manifest.json` records
//!   `{path,size,sha256,blake3}` for every member except itself, `release.sig`, and
//!   `release.crt`. The **release signature** (ed25519) covers the manifest's exact
//!   bytes, so it transitively covers every payload, evidence file, `core.json`, and
//!   every approval statement/signature/certificate. **A single changed byte in any
//!   covered member fails verification before the signature is even checked.**
//! * **Verification** is a fixed, fail-closed order (see [`verify`]) and always
//!   operates over the exact stored bytes — never a reparse-and-reserialize.
//! * **Anti-rollback.** [`rollback`] keeps per-`(supplier, product)` accepted state
//!   so a lower sequence, a same-sequence-different-bytes replay, or a bundle-id
//!   reuse is rejected at import.
//!
//! The signature algorithm is standard ed25519 (RustCrypto `ed25519-dalek`); signer
//! identity is a standard X.509 certificate. No new cryptographic algorithm and no
//! proprietary signature format are introduced.

pub mod api;
pub mod approval;
pub mod cli;
pub mod container;
pub mod core;
pub mod digest;
pub mod error;
pub mod finalize;
pub mod manifest;
pub mod pathsafe;
pub mod policy;
pub mod prepare;
pub mod receipt;
pub mod rollback;
pub mod schema;
pub mod signer;
pub mod time;
pub mod verify;

pub use api::{
    extract_bundle_file, extract_bundle_file_at, verify_bundle_file, verify_bundle_file_at,
    write_members_to_empty_dir,
};
pub use container::{atomic_write, load_bundle, pack_bundle, MemberMap};
pub use core::{BundleCore, EvidenceKind};
pub use error::{BundleError, Result};
pub use policy::{CertificateValidity, TrustMode, TrustPolicy};
pub use rollback::{AcceptedEntry, AcceptedState, Admissibility, RollbackStore};
pub use time::{HostRtc, TimeError, TrustedTime, HOST_RTC_NAME};
pub use verify::{
    verify_member_map, verify_member_map_with_time, ApprovalRecord, TargetSpec, VerifyReport,
};

#[cfg(test)]
mod tests;