Gunnar

nordisk/znippy

.nornir/signing-guide.md

# Provenance signing — guide

> **Class:** `guide` · audience: a techie signing an archive and verifying provenance.
> The *what* is in [`signing-design.md`](signing-design.md); siblings [`plugins-guide.md`](plugins-guide.md) · [`iceberg-guide.md`](iceberg-guide.md).

![znippy system](assets/znippy-system.svg)

## f0 — sign on write, verify on read (the whole workflow)

Signing is a **detached CMS** authenticity layer on top of the per-chunk blake3 integrity.
It is off by default; build with the `sign` feature:

```bash
cargo build --features sign
```

You need a **PKCS#8 DER key** and its **X.509 cert (DER)** to sign, and at least one trusted
**root CA (DER)** to verify.

## f1 — signing an archive

```bash
znippy compress -i <dir> -o out.znippy \
    --sign <pkcs8-key.der> --sign-cert <cert.der> [--sign-alg p256|ed25519]
```

- `--sign-alg` is `p256` (default) or `ed25519`.
- The signature is a **merkle fold of the chunk hashes already computed** — signing adds no
  content re-read and does not touch blob bytes.
- Omit `--sign` and the archive is **byte-identical** to an unsigned build.

CLI entry: `znippy-cli/src/lib.rs` `Commands::Compress` `--sign` / `--sign-cert` /
`--sign-alg` (`:82-91`).

## f2 — verifying provenance

```bash
znippy verify -i out.znippy --signed --root <ca.der> [--root <ca2.der> …]
```

- `--signed` turns on signature checking; at least one `--root` is required.
- verify **recomputes every artifact digest + the archive digest from the index** and
  checks the detached CMS against the trusted roots — tamper with any chunk hash or artifact
  and the archive root no longer matches.

CLI entry: `znippy-cli/src/lib.rs` `Commands::Verify` `--signed` / `--root` (`:142-147`).

## f3 — signing survives sealing

A signed archive round-trips through `seal` unchanged in trust: the merkle root is
content-derived and stable, so verify the **sealed** artifact exactly as above:

```bash
znippy seal -i sidecar.znippy --warehouse <dir> -o sealed.znippy
znippy verify -i sealed.znippy --signed --root <ca.der>
```

Round-trip coverage: `seal_signed_archive_round_trip`, `holger_verifies_a_served_artifact`.