anhedonic

dynamic soap bubbles

Jul 14, 2018

RPM Packages"">Batch Signing RPM Packages

Berend De Schouwer

Who is this post for?

Anyone who wants to distribute multiple signed RPM packages on RHEL 7 or earlier. [1]

What is Packaging?

Publishing software as a package is always a good idea. It allows for a much better user experience.

Normal software delivery follows:

  • write
  • build
  • test
  • package
  • distribute
  • use
  • bugreports

Packaging improves distribution. It makes it easier for users to install, and it provides for a consistent experience.

What is RPM?

RPM is the package format used by RedHat.

What is Signing?

Distributing the package opens up some security problems. We want to ensure that what the user uses is also what the developer distributes.

To do that, we need to sign the package.

This is often done with GPG, which is the defacto public/private key application. It’s also what RPM uses to sign.

What is gnupg-agent?

gnupg is the GNU implementation of GPG, and can be found at https://gnupg.org/

To sign — or encrypt — any file a user-known secret called a passphrase is required. gnupg acts on one file at a time, so when a lot of files are processed a lot of passphrases are required.

gnupg-agent is a program that — for a short time — remembers your passphrase. This is very convenient when processing a few hundred files.

Expectation

The expectation is to pre-load gnupg-agent, and then run RPM sign. We can preload gnupg-agent with gpg-preset-passphrase, and sign using rpmsign, so we expect:

echo $passphrase | /usr/bin/gpg-preset-passphrase --preset $grip
rpmsign $package_rpm

Of course, this doesn’t work. So let’s go through all the steps needed to make it work.

Binary Preset

The first problem is that gpg-preset-passphrase is in /usr/libexec/ and not /usr/bin/. This is easy to fix.

The second problem is that it doesn’t accept --preset isn’t accepted by default. Your config file ~/.gnupg/gpg-agent.conf needs to allow it with allow-preset-passphrase.

Grip, not ID

The next problem is that gpg-preset-passphrase needs a keygrip, not a key ID. So, lets get one:

gpg --list-keys --with-keygrip user@domain
  pub   rsa2048 2017-04-21 [SC]
        DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
        Keygrip = 1234BEEF1234BEEF1234BEED1234BEEF1234BEEF
  uid          [ultimate] <user@domain>
  sub   rsa2048 2017-04-21 [E]
        Keygrip = DEAD5678DEAD5678DEAD5678DEAD5678DEAD5678

If gpg doesn’t accept --with-keygrip you should look for fingerprints, and use those.

On RHEL 5 you need to use the main key. RPM doesn’t support some later key features. on RHEL >=6 use the subkey, that’s use DEAD5678DEAD5678DEAD5678DEAD5678DEAD5678.

getpass()

Now that we’ve preloaded the passphrase, we find that rpmsign still asks for a passphrase(!)

$ rpmsign $package_rpm
Enter pass phrase:

RPM < 4.13 will always ask for a passphrase before attempting to sign [2]. This was removed for a number of reasons:

  • getpass(3) is obsolete in glibc 2.2
  • it won’t work with GnuPG >= 2.1 with the defaults

So we remove it using an LD preload trick:

#include <stdio.h>

char empty[1024] = ""; /* size should be PASS_MAX; machine too old */

char * getpass (const char * prompt) {
    return empty;
}

Compile with:

gcc -shared -fPIC getpass-noopc. -o libgetpass-noop.so

and run

LD_PRELOAD=~/lib/libgetpass-noop.so rpmsign $package_rpm

%__gpg_check_password_cmd

RPM then verifies the passphrase independently of GnuPG. It doesn’t actually try to sign, it first verifies.

Signing would fail with a bad passphrase, but RPM will verify first.

The problem is that a bad verification will remove a valid passphrase from gpg-agent. So we need to prevent a bad verification.

We do that by editing the rpm macro ~/.rpmmacros:

%__gpg_check_password_cmd ~/bin/readoneline.sh  ~/bin/readoneline.sh

and create a very simple shell script readoneline.sh:

#!/bin/sh
read LINE
exit 0

Footnotes

[1]After RHEL 7 a number of problems in this post have been fixed, in RPM >= 4.13. [2]
[2](1, 2) getpass(3) is no longer used in RPM >= 4.13, see: https://github.com/rpm-software-management/rpm/commit/0bce5fcf270711a2e077fba0fb7c5979ea007eb5
posted at 13:45  ·   ·  rpm  deprecated  gpg