Skip to content

pkgdev:signing

Jonathan Perkin edited this page Apr 6, 2018 · 8 revisions

Contents

  1. Introduction
  2. Setup
  3. Create PGP Key
  4. Configure GnuPG
  5. Configure pkgbuild
  6. Test Package Signing
  7. Offline Signing

Introduction

This guide shows how to set up PGP signing of packages in a pkgbuild environment. If you aren't using pkgbuild, there should be enough details here to get you started.

Setup

In a pkgbuild zone, but not inside a sandbox, install GnuPG from pkgsrc, as the one provided by the platform is too old and incomplete. Note that GnuPG broke compatibility between 2.0 and 2.2 so you need to specify the exact package depending on your pkgsrc release.

# If you are running 2017Q3 or newer
$ pkgin -y install gnupg20

# Otherwise for 2017Q2 and older
$ pkgin -y install gnupg2

Note that the command installed from pkgsrc is gpg2, while gpg will still be the one from the platform in /usr/bin/gpg.

Create PGP Key

Create a new PGP key that will be used to sign your packages. Obviously use your own email address and comment instead of the ones shown here. You will be asked to set a password, make sure it is highly secure (e.g. pwgen -sy 64 using the pwgen package from pkgsrc). The GPG agent will cache it so you do not need to type it in every time.

$ gpg2 --gen-key

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: My Package Key
Email address: pkgsrc@example.com
Comment:
You selected this USER-ID:
    "My Package Key <pkgsrc@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

gpg: key F527BD41 marked as ultimately trusted
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   4096R/F527BD41 2017-04-21
      Key fingerprint = A84D 1638 63E2 420A B0EB  047D 3349 5548 F527 BD41
uid       [ultimate] My Package Key <pkgsrc@example.com>
sub   4096R/5704520E 2017-04-21

Configure GnuPG

To enable automatic signing of packages without having to type in the password every time we can configure gpg-agent to cache the password. Follow these instructions if you wish to do so.

Configure /root/.gnupg/gpg-agent.conf:

daemon
use-standard-socket
max-cache-ttl 315360000
default-cache-ttl 315360000
pinentry-program /opt/local/bin/pinentry-tty

Configure /root/.gnupg/gpg.conf:

lock-never
no-auto-check-trustdb
no-random-seed-file
no-tty
keyserver hkp://keys.gnupg.net

Launch the agent and cache the password

$ gpg-agent
$ echo "hi" >f
$ gpg2 --sign f

: Test that subsequent runs do not prompt for the password
$ rm -f f.gpg
$ gpg2 --sign f

: Check the signature
$ gpg2 --verify f.gpg
gpg: Signature made Fri Apr 21 08:57:07 2017 UTC using RSA key ID F527BD41
gpg: Good signature from "My Package Key <pkgsrc@example.com>" [ultimate]

$ rm -f f{,.gpg}

Configure pkgbuild

The final part is to configure pkgbuild to use the key we have generated. If you do not wish to sign inline and prefer to sign packages separately, skip this part and go straight to the offline signing section.

Add to mk.conf.local for your target build (e.g. /data/pkgbuild/conf/2017Q4-x86_64/mk.conf.local):

SIGN_PACKAGES=gpg

Add to pkgbuild.conf.local for your target build (e.g. /data/pkgbuild/conf/2017Q4-x86_64/pkgbuild.conf.local):

# Was previously named PKGSRC_GPG_SIGN_AS, use that if using an older pkgbuild.
PKGBUILD_GPG_SIGN_AS=F527BD41

Test Package Signing

Let's now check that everything works as expected.

Start the sandbox:

$ run-sandbox 2017Q4-x86_64

Build a small package:

$ cd /data/pkgsrc/pkgtools/digest
$ bmake package
[...]
===> Building binary package for digest-20160304
=> Creating binary package /data/packages/SmartOS/2017Q4/x86_64/All/digest-20160304.tgz
pkg_info: unable to verify signature: Signature key id 33495548f527bd41 not found
*** Error code 1

At this point we are successfully signing the package, but the install is failing because our new key is not yet trusted by the packaging tools.

Import the new key into the pkgsrc keyring (as configured in /opt/local/etc/pkg_install.conf):

$ gpg2 --export F527BD41 | \
  gpg2 --no-default-keyring \
       --keyring=/opt/local/etc/gnupg/pkgsrc.gpg \
       --import -

Then try to install the package again. This time it should complete successfully with no errors:

$ pkg_add /data/packages/SmartOS/2017Q4/x86_64/All/digest-20160304.tgz

You will need to install this updated keyring onto any host that uses your signed packages.

Offline Signing

Some people prefer not to sign packages inline, usually because their security policies don't permit cached passwords, or they do not allow the build hosts to have access to the signing key. If you prefer to leave signing to a separate step, ensure you have not configured pkgbuild with SIGN_PACKAGES=gpg as described above.

Build the unsigned package in a sandbox then exit it.

$ run-sandbox 2017Q4-x86_64
$ cd /data/pkgsrc/pkgtools/digest
$ bmake package
[...]
===> Building binary package for digest-20160304
=> Creating binary package /data/packages/SmartOS/2017Q4/x86_64/All/digest-20160304.tgz
$ exit

Configure /opt/local/etc/pkg_install.conf (wherever you have chosen to perform the signing) with your key details:

GPG=/opt/local/bin/gpg2
GPG_SIGN_AS=F527BD41

Sign the package. Note the different file formats, unsigned packages are ordinary compressed tarballs, whereas signed packages are ar(1) archives of the compressed tarball plus the signing files.

$ mkdir signed unsigned
$ cp /data/packages/SmartOS/2017Q4/x86_64/All/digest-20160304.tgz unsigned
$ pkg_admin gpg-sign-package unsigned/digest-20160304.tgz signed/digest-20160304.tgz
$ file unsigned/digest-20160304.tgz signed/digest-20160304.tgz
unsigned/digest-20160304.tgz:	gzip compressed data - deflate method
signed/digest-20160304.tgz:	current ar archive, not a dynamic executable or shared object