The Ur Project

Documenting the craft of stacking things so they remain stacked. For a very long time.

pkg-verify-sig(1)

NAME

pkg-verify-sig - verify the signature on a package manifest

SYNOPSIS

pkg verify-sig manifest

DESCRIPTION

Every manifest ends in a signature block: the algorithm, the public key that signed it, and the signature itself. This command reads a manifest, decodes that key and that signature, and checks the signature over the manifest.

What does it actually prove?

Less than you'd hope. This checks that the manifest is intact, not who signed it. The manifest names its own key, and that's the key it gets checked against. A manifest signed by an attacker's key verifies perfectly.

So use it to answer "is this file intact, and which key claims it". Whether that's the right key is a separate question, and other parts of the system answer it:

  • For a remote repository, the TUF trust anchor does; see pkg-repo(1) and pkg-repos.d(5).
  • For a composition, pkg compose --trust-key does. It fails any manifest that isn't signed by a key you named.
  • For a published build, pkg-provenance(1) does, by verifying the signed record that binds the outputs to their inputs.

What is signed?

Not the bytes of the file. The manifest is parsed and put back into its canonical form, with the signature value cleared, and that's what the signature covers. The algorithm and the public key are part of it, so a signature is bound to the key that made it.

That means a comment, extra whitespace or reordered keys don't break the signature. They don't change what the manifest says. Change any value, though, a release number, a file's hash, a path, and it fails.

OPTIONS

No options of its own. All global options apply; see pkg(1).

OUTPUT

signature valid: /srv/build/pkg-meta (pubkey 3a7f...c2e1)

On failure it exits 1, with a message on stderr saying what went wrong: a manifest that doesn't parse, a public key or signature that doesn't decode, an algorithm other than ed25519, or a signature that doesn't verify:

error: sign: signature verification failed

JSON

{ "ok": true, "manifest": "/srv/build/pkg-meta", "public_key": "3a7f...c2e1", "valid": true }

EXAMPLES

One manifest

pkg verify-sig /srv/repo/Common/pkgs/gzip/bin/1.13/4/x86_64/pkg-meta

Installed manifests work the same way:

pkg verify-sig /var/lib/pkg/installed/gzip/bin/manifest.toml

Which key signed it

pkg --json verify-sig \ /srv/repo/Common/pkgs/gzip/bin/1.13/4/x86_64/pkg-meta \ | jq -r .public_key

A whole repository

find /srv/repo/Common/pkgs -name pkg-meta -print0 \ | xargs -0 -n1 pkg verify-sig > /dev/null

Or, keeping only the failures:

find /srv/repo/Common/pkgs -name pkg-meta -print0 \ | while IFS= read -r -d '' m; do pkg verify-sig "$m" > /dev/null 2>&1 || echo "FAIL $m" done

Is it all signed by one key?

find /srv/repo/Common/pkgs -name pkg-meta -print0 \ | xargs -0 -n1 pkg --json verify-sig \ | jq -r .public_key | sort -u

Two lines during a key rotation is expected. Two lines any other time is worth looking into.

After signing

pkg sign /srv/build/gzip/bin/pkg-meta --key /etc/pkg/keys/release.key pkg verify-sig /srv/build/gzip/bin/pkg-meta

A bundle somebody handed you

mkdir /tmp/scratch && tar -xf /mnt/usb/console.pkgtar -C /tmp/scratch find /tmp/scratch/pkgs -name pkg-meta -print0 \ | xargs -0 -n1 pkg --json verify-sig | jq -r .public_key | sort -u

Now compare that key against the one you expected. That's the step that turns "the file is intact" into "the file is ours".

Seeing tampering get caught

m=/tmp/scratch/pkgs/bash/bin/5.3/4/x86_64/pkg-meta sed -i 's/release = 4$/release = 5/' "$m" pkg verify-sig "$m"

  • One value changed, and the signature fails

Appending a comment to the same file would not have failed it. A comment isn't part of what's signed.

The whole trust chain for one package

pkg verify-sig /srv/repo/Common/pkgs/gzip/bin/1.13/4/x86_64/pkg-meta pkg provenance verify gzip pkg verify gzip

In order: the manifest is intact and names a key, the build is bound to signed inputs whose hashes check out, and the files on disk match the manifest.

EXIT STATUS

0 when the signature verifies, 1 otherwise.

SEE ALSO

pkg(1), pkg-sign(1), pkg-verify(1), pkg-provenance(1), pkg-info(1), pkg-repo(1), pkg-repos.d(5), pkg-repository-layout(7)

docs/design/trust.md, docs/components/pkg-sign.md