Rpmsign with CLI password prompt

command linegnupgpasswordrpmscripting

I working on a Fedora 25 (F25) workstation, the KDE spin. I'm writing some scripts to perform automated testing.

One of the automated tests involves invoking the RPMSIGN(8) program which in turn invokes GPG(1) to attach a digital signature to some RPM files I am creating. Of course, GPG uses pinentry (PIN entry) to prompt the human to enter the passphrase for the RPM signing key (an RSA key pair). I want to take the human out of the loop and fully automate the task of supplying the passphrase for the RPM signing key.( And yes, I know about the security implications. This is simply an automated test environment and not a production host, so I'm not overly concerned about security. In the production version the user will manually enter the RPM signing key's password.)

In the past I used an EXPECT(1) script that waited for GPG to ouptut the text "Enter pass phrase:" to the console, and then the EXPECT script would enter the pass phrase and on I'd go. Worked great.

In F25 the pinentry feature breaks my existing EXPECT-based solution for automated entry of the passphrase for the RPM signing key.

When I run RPMSIGN in a GUI console window on this F25 host, GPG uses pinentry to pop up a GUI dialog box that asks the user (me) to enter the passphrase for the RPM signing key. This pinentry behavior, of course, interferes and prevents automated entry of the passphrase.

If I create a Bash script that momentarily unsets the DISPLAY environment variable, then I no longer get the GUI dialog,

#!/bin/bash
DISPLAY_SAVE=$DISPLAY
unset DISPLAY
rpmsign --resign "/path/to/test-1.0.0-1.fc25.noarch.rpm"
export DISPLAY=$DISPLAY_SAVE

but now I get an ncurses version of the dialog on the console:

+----------------------------------------------------------------+
| Please enter the passphrase to unlock the OpenPGP secret key:  |
| "Testing (rpm-sign)"                                           |
| 1024-bit RSA key, ID 0123456789ABCDEF,                         |
| created 2016-12-02.                                            |
|                                                                |
|                                                                |
| Passphrase: __________________________________________________ |
|                                                                |
|         <OK>                                    <Cancel>       |
+----------------------------------------------------------------+

Again, pinentry-curses's console "dialog" interferes and prevents automated entry of the passphrase.

I don't want to permanently modify or disable the pinentry modules; I just want to disable them temporarily to get back to GPG's CLI prompt "Enter pass phrase:" (or whatever that prompt string is now) without pinentry interfering.

Any suggestions for fully automating the entry of the RPM signing key's passphrase via the CLI without pinentry interference?

Best Answer

Thanks to @Joe Damato for pointing me toward the gpg-preset-passphrase utility. The solution described below was developed and tested on a Fedora 25 host with gnupg2-2.1.x installed.

(n.b. I haven't yet figured out how to determine the RPM signing key's keygrip value on platforms running older versions of GnuPG because they don't support the --with-keygrip option. If someone would like to comment on a solution for this, please do.)

Ensure ~/.gnupg/gpg-agent.conf contains the line.

allow-preset-passphrase

After modifying ~/.gnupg/gpg-agent.conf reload the gpg-agent.

$ gpg-connect-agent reloadagent /bye
OK

List your GPG keys to obtain the eight hexidecimal digit key ID for your RPM signing key. In this excample, the key ID is 0123ABCD.

$ gpg --list-keys
/home/me/.gnupg/pubring.gpg
-----------------------------------
pub   1024R/0123ABCD 2015-06-13
uid                  Test (rpm-sign)

Get the keygrip code for the RPM signing key. (n.b. On the RHEL 7.2 and Fedora 20 hosts I use for testing, the GPG2(1) program on those hosts didn't recognize the --with-keygrip option.)

$ gpg2 --with-keygrip -K 0123ABCD
sec   rsa1024 2015-06-13 [SCEA]
      0A1B2C3D4E5F6A7B8C9D0E0F1A2B3C4D0123ABCD
      Keygrip = 2EACA0C5A4B46168EB91970B6715AF1AA52968BE
uid           [ unknown] Test (rpm-sign)

Cache the passphrase for the RPM signing key. In the command line shown below, replace 'PASSPHRASE' with the actual passphrase for the RPM signing key.

$ /usr/libexec/gpg-preset-passphrase --passphrase 'PASSPHRASE' --preset 2EACA0C5A4B46168EB91970B6715AF1AA52968BE

:: TEST ::

Create a test RPM file that is not signed. Verify that the test RPM file is not signed.

$ rpm --checksig test-1.0.0-1.f25.noarch.rpm
test-1.0.0-1.fc25.noarch.rpm: sha1 md5 OK

Verify that RPMSIGN(8) uses the cached password--i.e., that RPMSIGN(8) does not prompt you to enter the passphrase for the RPM signing key--when signing the test RPM file.

$ rpmsign --resign test-1.0.0-1.f25.noarch.rpm

Verify that the test RPM file is signed.

$ rpm --checksig test-1.0.0-1.f25.noarch.rpm
test-1.0.0-1.fc25.noarch.rpm: rsa sha1 (md5) pgp md5 OK

:: ADDENDUM 1 (2016-12-17) ::

According to this GnuPG Issue 2331 webpage:

gpg1 does not known about keygrips. Instead of the keygrip, gpg1 uses the fingerprint as cacheid for gpg-agent. The agent's command GET_PASSPHRAE, as used by gpg1, uses a different cache mode from what gpg-preset-passphrases uses. Thus even if you replace the keygrip with the fingerprint of the (sub)key, it won't work.

For what it's worth, I've done some testing with GnuPG version 2.0.x on RHEL7 hosts and gpg-preset-passphrase doesn't seem to be supported. I can only get gpg-preset-passphrase to work with GnuPG version 2.1.x.

References

GnuPG ArchWiki

Related Question