You can sign RPM files with a virtual GPG key and the Signum Linux Agent.
The link between the GPG virtual key and the Signum key is the keygrip which is the GnuPG internal identifier computed from the raw RSA key material (modulus + exponent). Since both sides are working with the same underlying RSA key pair, they produce the same keygrip, which is how GPG identifies the virtual key as the key in Signum.
The GPG Key ID and the Signum certificate thumbprint are different identifiers computed in different ways from the same key material. There is no automatic correlation between them.
Prerequisites
-
Signum Linux Agent
-
Linux distribution supported by the Linux Agent
-
sudoprivileges
Step 1 - Install Dependencies
-
Install the packages:
sudo apt update
sudo apt install -y \
gnupg2 \
pinentry-curses \
opensc \
build-essential \
bzip2 \
wget \
devscripts \
libgpg-error-dev \
libgcrypt20-dev \
libassuan-dev \
libpkcs11-helper1-dev \
pkg-config
-
Build gnupg-pkcs11-scd 0.11.0 from source with a one-line patch in
cmd_keyinfo:
The version of gnupg-pkcs11-scd available in Debian apt repositories is 0.10.0 and has a known bug. Version 0.11.0 partially fixes this but still requires a one-line patch in cmd_keyinfo.
cd /tmp
wget https://github.com/alonbl/gnupg-pkcs11-scd/releases/download/gnupg-pkcs11-scd-0.11.0/gnupg-pkcs11-scd-0.11.0.tar.bz2
tar -xjf gnupg-pkcs11-scd-0.11.0.tar.bz2
cd gnupg-pkcs11-scd-0.11.0
# Apply the patch
python3 << 'EOF'
with open('gnupg-pkcs11-scd/command.c', 'r') as f:
content = f.read()
old = '\t\tif (error != GPG_ERR_NO_ERROR) {\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\terror = found ? GPG_ERR_NO_ERROR : GPG_ERR_NOT_FOUND;'
new = '\t\tif (error == GPG_ERR_WRONG_PUBKEY_ALGO) {\n\t\t\terror = GPG_ERR_NO_ERROR;\n\t\t}\n\t\tif (error != GPG_ERR_NO_ERROR) {\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\terror = found ? GPG_ERR_NO_ERROR : GPG_ERR_NOT_FOUND;'
if old in content:
content = content.replace(old, new)
with open('gnupg-pkcs11-scd/command.c', 'w') as f:
f.write(content)
print("Patch applied!")
else:
print("Pattern not found!")
EOF
# Build and install
./configure && make && sudo make install
# Verify
/usr/local/bin/gnupg-pkcs11-scd --version
Expected output:
gnupg-pkcs11-scd 0.11.0
Step 2 - Verify Signum Agent and PKCS#11 Library
-
Verify the Agent is authenticated and certificates are visible:
signum-util test
signum-util listcertificates
-
Verify the PKCS#11 library is present and keys are accessible:
ls -la /usr/lib/libsignumpkcs11.so
pkcs11-tool --module /usr/lib/libsignumpkcs11.so --list-objects
Step 3 - Create GPG Configuration Files
-
Create the GPG configuration files:
mkdir -p ~/.gnupg
chmod 700 ~/.gnupg
cat > ~/.gnupg/gpg-agent.conf << 'EOF'
verbose
debug-all
log-file /tmp/gpg-agent.log
scdaemon-program /usr/local/bin/gnupg-pkcs11-scd
pinentry-program /usr/bin/pinentry-curses
allow-loopback-pinentry
EOF
cat > ~/.gnupg/gnupg-pkcs11-scd.conf << 'EOF'
providers signum
provider-signum-library /usr/lib/libsignumpkcs11.so
EOF
chmod 600 ~/.gnupg/gpg-agent.conf
chmod 600 ~/.gnupg/gnupg-pkcs11-scd.conf
-
Set GPG_TTY and start the smart card daemon:
GPG_TTY must always be set before signing.
export GPG_TTY=$(tty)
gpgconf --kill all
gpg --card-status
Expected result is the card detected with Application type: OpenPGP.
-
Get the
KEY-FRIENDLYhash for your certificate from Signum:
gpg-connect-agent << 'EOF'
SCD LEARN --force
SCD GETATTR KEYPAIRINFO
EOF
Note the KEY-FRIENDLY hash for the certificate you want to use:
S KEY-FRIENDLY 2588F2F67BBC82E872B15287621964636FB074D9 /CN=SignumCertificate on Signum for Linux
Save this hash for the following steps.
Step 4 - Map the Signing Key
Update gnupg-pkcs11-scd.conf with the KEY-FRIENDLY hash:
-
Replace
<KEY-FRIENDLY-HASH>with your actual hash value:
cat > ~/.gnupg/gnupg-pkcs11-scd.conf << 'EOF'
providers signum
provider-signum-library /usr/lib/libsignumpkcs11.so
openpgp-sign <KEY-FRIENDLY-HASH>
EOF
-
Restart the daemon to apply the change:
gpgconf --kill all
gpg --card-status
-
Confirm the
Signature keyfield is now populated. It should show the keygrip instead of[none]:
Signature key ....: 2588 F2F6 7BBC 82E8 72B1 5287 6219 6463 6FB0 74D9
Step 5 - Create the Virtual GPG Key
-
Generate the virtual GPG key:
gpg --expert --full-generate-key
-
When prompted, provide the following values:
|
Prompt |
Value |
|---|---|
|
Key type |
|
|
Keygrip |
|
|
Capabilities |
|
|
Expiry |
|
|
Real name |
Your full name |
|
Email address |
Your email address |
|
Confirm |
|
|
PIN prompt |
Your Signum password |
Expected output:
pub rsa2048 2026-05-05 [SCE]
EF9365EAB0975DE4ED1D241B431698166BB91279
uid Your Name <your@email.com>
-
Verify the key is linked to the Signum card:
gpg --list-secret-keys --with-keygrip
Confirm sec> (with >) appears, meaning the private key is in the Signum HSM, not on disk:
sec> rsa2048 2026-05-05 [SCE]
EF9365EAB0975DE4ED1D241B431698166BB91279
Keygrip = 2588F2F67BBC82E872B15287621964636FB074D9
Card serial no. = 3131 DC6624E9
uid [ultimate] Your Name <your@email.com>
-
Set this key as the GPG default. Replace
<FINGERPRINT>with the full fingerprint
from the output above:
echo "default-key <FINGERPRINT>" >> ~/.gnupg/gpg.conf
echo "default-key EF9365EAB0975DE4ED1D241B431698166BB91279" >> ~/.gnupg/gpg.conf
-
Make GPG_TTY permanent across sessions:
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
source ~/.bashrc
Step 6 - Configure RPM Macros
If your Linux distribution does not natively use RPM, you must first create a directory:
sudo mkdir /etc/rpm
Create the macro file, replacing Your name and <your_email> with your actual values:
cat > ~/.rpmmacros << 'EOF'
%_signature gpg
%_gpg_path /home/<username>/.gnupg
%_gpg_name Your name <your_email>
%_gpgbin /usr/bin/gpg2
%__gpg_sign_cmd %{__gpg} gpg --force-v3-sigs --batch --verbose --no-armor --no-secmem-warning -u "%{_gpg_name}" -sbo %{__signature_filename} --digest-algo sha256 %{__plaintext_filename}
%_dbpath /var/lib/rpm
EOF
echo "%_dbpath /var/lib/rpm" | sudo tee /etc/rpm/macros.db
The %_gpg_name value must match the UID of your GPG key exactly, including
the email address in single angle brackets. Use gpg --list-keys to confirm the
exact UID string.
Step 7 - Import the Public Key into the RPM Keyring
Export your public key and import it into the RPM database so rpm --checksig can
verify signatures against it:
gpg --armor --export <your_email> > /tmp/signum-pubkey.asc
sudo rpm --import /tmp/signum-pubkey.asc --dbpath /var/lib/rpm
Verify the key was imported:
rpm -q gpg-pubkey --dbpath /var/lib/rpm \
--qf '%{name}-%{version}-%{release} --> %{summary}\n'
Expected output:
gpg-pubkey-6bb91279-69f99e75 --> Your Name <your@email.com> public key
Step 8 - Sign an RPM
-
Sign the
.rpm:
rpmsign --addsign /path/to/yourpackage.rpm
-
Verify the RPM signature:
rpm --checksig --verbose /path/to/yourpackage.rpm
rpm --checksig /path/to/yourpackage.rpm
Expected output:
Header V4 RSA/SHA256 Signature, key ID 6bb91279: OK
Header SHA256 digest: OK
Payload SHA256 digest: OK
digests signatures OK
Troubleshooting
rpmsign Fails with "key not found" or "secret key not available"
-
Confirm
%_gpg_namein~/.rpmmacrosmatches the GPG key UID exactly:
gpg --list-keys -
The UID format must be: Your Name <your@email.com> (single angle brackets).
Double brackets or extra spaces will cause the lookup to fail. -
Confirm GPG_TTY is exported in the current shell before running
rpmsign.
rpm --checksig Shows "NOKEY" or Signature Verification Fails
-
Confirm the public key was imported into the RPM keyring:
rpm -q gpg-pubkey --dbpath /var/lib/rpm -
If the key is missing, re-run the import:
sudo rpm --import /tmp/signum-pubkey.asc --dbpath /var/lib/rpm -
Check that the key ID in the checksig output matches the version field of the imported key (such as 6bb91279).
rpmsign Prompts for a Passphrase Interactively and Hangs in CI
-
Confirm
allow-loopback-pinentryis set ingpg-agent.conf. -
Confirm
--batchis present in the%__gpg_sign_cmdmacro in~/.rpmmacros. -
In a CI environment, ensure GPG_TTY is set and a pinentry program is available:
export GPG_TTY=$(tty)
RPM Was Signed but Signature Appears as "gpg" Not "RSA/SHA256"
-
The
--force-v3-sigsflag in%__gpg_sign_cmdproduces v3 OpenPGP signatures,
which older RPM versions require. If your RPM toolchain supports v4 signatures,
remove --force-v3-sigsfor stronger compatibility with modern verification tools.