The Ur Project

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

pkg-sign(1)

NAME

pkg-sign - sign a package manifest

SYNOPSIS

pkg sign manifest --key FILE

DESCRIPTION

Signs a package manifest in place, with an Ed25519 key.

This is a tool for whoever produces packages. pkg-build(1) already signs everything it emits with your build key, so you'd reach for this to sign a manifest by hand, or to re-sign one with a different key. An ordinary client machine never needs it.

What happens to the file?

The manifest is read and parsed. Its signature block gets the public half of your key, the manifest is signed in its canonical form, and the result is written back atomically: to a temporary file first, then renamed over the original.

What lands on disk is the canonical serialization, not your original text. Comments and formatting don't survive. That's on purpose: the canonical form is what pkg-verify-sig(1) and everything else verifies against, so it's what should be on disk.

OPTIONS

--key FILE
Required. The Ed25519 private key: exactly 32 raw bytes, the seed. Not PEM, not hex, not OpenSSH format. A file of any other length is refused, and the error tells you the length it found. pkg-keygen(1) writes keys in this format.

All global options apply; see pkg(1).

KEY HANDLING

The private key is 32 raw bytes sitting on disk. Treat it like that: restrictive permissions, never in a repository, never in your shell history, never pasted on a command line.

You don't pass the public key anywhere. It's derived from the private one, and printed after signing. That printed hex string is exactly what pkg compose --trust-key wants.

OUTPUT

signed /srv/build/pkg-meta with 3a7f...c2e1

JSON

{ "ok": true, "manifest": "/srv/build/pkg-meta", "public_key": "3a7f...c2e1", "signature": "9d41...80ab" }

EXAMPLES

One manifest

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

Checking the result

pkg verify-sig /srv/build/gzip/bin/pkg-meta

Grabbing the public key for a compose

PUBKEY=$(pkg --json sign /srv/build/gzip/bin/pkg-meta \ --key /etc/pkg/keys/release.key | jq -r .public_key) pkg compose root --output /srv/roots/x \ --closure gzip --trust-key "$PUBKEY"

A whole tree of manifests

find /srv/build -name pkg-meta -print0 \ | xargs -0 -I{} pkg sign {} --key /etc/pkg/keys/release.key

And verifying it afterwards:

find /srv/build -name pkg-meta -print0 \ | xargs -0 -n1 pkg verify-sig

Is this key file the right shape?

stat -c %s /etc/pkg/keys/release.key

It has to say 32. Anything else is refused:

error: invalid argument: /etc/pkg/keys/release.key is 64 bytes; a key file is 32 raw bytes, the Ed25519 seed

Re-signing after a key rotation

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

During the overlap, a compose can trust both:

pkg compose root --output /srv/roots/x --closure gzip \ --trust-key "$OLD_PUBKEY" --trust-key "$NEW_PUBKEY"

EXIT STATUS

0 on success. 1 when the key file isn't 32 bytes, the manifest doesn't parse, or the write fails.

SEE ALSO

pkg(1), pkg-verify-sig(1), pkg-keygen(1), pkg-build(1), pkg-compose(1), pkg-info(1), pkg-provenance(1), pkg-repository-layout(7)

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