Skip to content

Commit

Permalink
Support automatic signing on build when _openpgp_autosign_id is set
Browse files Browse the repository at this point in the history
Ideally the signing would happen in parallel, but as the signing code
relies heavily on macro manipulation, that's a much bigger task for some
other time.

I think we'd rather use an rpm specific keyring for the
automatic signing, but this is difficult to arrange with how the signing
macros work.

Set up auto-signing inside the test-suite throughout, except for
the couple of reproducibility tests where this would be harmful.

Fixes: rpm-software-management#2678
  • Loading branch information
pmatilai committed Feb 14, 2025
1 parent 336c9e9 commit 6798e68
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 12 deletions.
32 changes: 32 additions & 0 deletions build/pack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
#include <rpm/rpmlib.h> /* RPMSIGTAG*, rpmReadPackageFile */
#include <rpm/rpmfileutil.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmsign.h>

#include "rpmio_internal.hh" /* fdInitDigest, fdFiniDigest */
#include "signature.hh"
#include "rpmlead.hh"
#include "rpmbuild_internal.hh"
#include "rpmbuild_misc.hh"
#include "rpmmacro_internal.hh"

#include "debug.h"

Expand Down Expand Up @@ -664,6 +666,23 @@ static rpmRC checkPackageSet(Package pkgs)
return rc;
}

static rpmRC signPackage(const char *fn)
{
int rc = 0; /* fall merrily through if signer not defined */
auto [ ign, sign_id ] = rpm::macros().expand("%{?_openpgp_autosign_id}");
if (sign_id.empty() == false) {
struct rpmSignArgs sa = {
.keyid = const_cast<char *>(sign_id.c_str()),
.hashalgo = {},
.signflags = {},
};
rc = rpmPkgSign(fn, &sa);
rpmlog(RPMLOG_DEBUG, "signing %s with %s: %d\n",
fn, sign_id.c_str(), rc);
}
return rc ? RPMRC_FAIL : RPMRC_OK;
}

/* watchout, argument is modified */
static rpmRC ensureDir(char *binRpm)
{
Expand Down Expand Up @@ -799,6 +818,16 @@ rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
if (rc == RPMRC_OK)
rc = checkPackageSet(spec->packages);

/* Finally, sign the packages. Signing is currently NOT thread-safe... */
if (rc == RPMRC_OK) {
for (auto & pkg : tasks) {
if (pkg->filename)
rc = signPackage(pkg->filename);
if (rc)
break;
}
}

return rc;
}

Expand Down Expand Up @@ -832,6 +861,9 @@ rpmRC packageSources(rpmSpec spec, char **cookie)
rc = checkPackages(pkgcheck);
}

if (rc == RPMRC_OK)
rc = signPackage(sourcePkg->filename);

free(pkgcheck);
}
return rc;
Expand Down
1 change: 1 addition & 0 deletions tests/data/macros.testenv
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
%_tmppath %{getenv:RPMTEST}/var/tmp
%_dbpath /var/lib/rpm-testsuite
%_keyring openpgp
%_keyringpath /var/lib/rpm-keyring
4 changes: 4 additions & 0 deletions tests/local.at
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ rm -rf "${RPMTEST}"`rpm --eval '%_dbpath'`
runroot rpm --initdb
])

m4_define([RPMKEYRING_RESET],[
rm -rf "${RPMTEST}"`rpm --eval '%_keyringpath'`
])

m4_define([RPMPY_RUN],[[
cat << EOF > test.py
# coding=utf-8
Expand Down
1 change: 1 addition & 0 deletions tests/pinned/common/buildrepr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ runroot rpmbuild -ba --quiet \
--define "source_date_epoch_from_changelog 1" \
--define "build_mtime_policy clamp_to_source_date_epoch" \
--define "_use_weak_usergroup_deps 0" \
--define "_openpgp_autosign_id %{nil}" \
/data/SPECS/attrtest.spec

2 changes: 1 addition & 1 deletion tests/rpmquery.at
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ import json
s = open('stdout').read()
print(len(json.loads(s)))
],
[58
[59
],
[])
RPMTEST_CLEANUP
Expand Down
29 changes: 20 additions & 9 deletions tests/rpmsigdig.at
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,10 @@ RPMTEST_CLEANUP

RPMTEST_SETUP_RW([rpmkeys migrate from keyid to fingerprint (fs)])
AT_KEYWORDS([rpmkeys rpmdb])
# use a keyring specific to this test
krpath=${PWD}/kr
echo "%_keyring fs" >> "${RPMTEST}"/"${RPMSYSCONFDIR}"/macros.testenv
krpath="$(rpm --eval %{_keyringpath})"
echo "%_keyringpath ${krpath}" >> "${RPMTEST}"/"${RPMSYSCONFDIR}"/macros.testenv

RPMTEST_CHECK([
runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub
Expand Down Expand Up @@ -273,8 +275,10 @@ RPMTEST_CLEANUP

RPMTEST_SETUP_RW([rpmkeys key update (openpgp)])
AT_KEYWORDS([rpmkeys signature])
# use a keyring specific to this test
krpath=${PWD}/kr
echo "%_keyring openpgp" >> "${RPMTEST}"/"${RPMSYSCONFDIR}"/macros.testenv
krpath=$(rpm --eval "%{_keyringpath}")
echo "%_keyringpath ${krpath}" >> "${RPMTEST}"/"${RPMSYSCONFDIR}"/macros.testenv

RPMTEST_CHECK([
runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub
Expand Down Expand Up @@ -1213,11 +1217,12 @@ RPMTEST_CLEANUP
RPMTEST_SETUP_RW([rpmsign --addsign])
AT_KEYWORDS([rpmsign signature])
RPMTEST_SKIP_IF([test x$PGP = xdummy])
echo "%_openpgp_sign gpg" >> $RPMTEST/root/.config/rpm/macros
gpg2 --import ${RPMTEST}/data/keys/rpm.org-rsa-2048-test.secret

# rpmsign --addsign --rpmv3 <unsigned>
RPMTEST_CHECK([
RPMDB_RESET
RPMKEYRING_RESET

cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/
runroot rpmsign --key-id 4344591E1964C5FC --rpmv3 --digest-algo sha256 --addsign /tmp/hello-2.0-1.x86_64.rpm
Expand Down Expand Up @@ -1246,7 +1251,7 @@ POST-DELSIGN

# rpmsign --addsign <unsigned>
RPMTEST_CHECK([
RPMDB_RESET
RPMKEYRING_RESET

cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/
runroot rpmsign --key-id 4344591E1964C5FC --digest-algo sha256 --addsign /tmp/hello-2.0-1.x86_64.rpm
Expand All @@ -1273,7 +1278,7 @@ POST-DELSIGN

# test --delsign restores the old package bit-per-bit
RPMTEST_CHECK([
RPMDB_RESET
RPMKEYRING_RESET

ORIG="/data/RPMS/hello-2.0-1.x86_64.rpm"
NEW="/tmp/hello-2.0-1.x86_64.rpm"
Expand Down Expand Up @@ -1309,7 +1314,7 @@ error: /gnus/not/here exec failed (1)

# rpmsign --addsign <signed>
RPMTEST_CHECK([
RPMDB_RESET
RPMKEYRING_RESET

cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64-signed.rpm "${RPMTEST}"/tmp/
runroot rpmsign --key-id 4344591E1964C5FC --digest-algo sha256 --addsign /tmp/hello-2.0-1.x86_64-signed.rpm 2>&1 |grep -q "already contains identical signature, skipping"
Expand All @@ -1322,7 +1327,7 @@ runroot rpmsign --key-id 4344591E1964C5FC --digest-algo sha256 --addsign /tmp/he
# This is behaves counter-intuitively / is buggy if md5 verification is
# disabled, see https://github.com/rpm-software-management/rpm/issues/3291
RPMTEST_CHECK([
RPMDB_RESET
RPMKEYRING_RESET

pkg="hello-2.0-1.x86_64.rpm"
cp "${RPMTEST}"/data/RPMS/${pkg} "${RPMTEST}"/tmp/${pkg}
Expand All @@ -1349,7 +1354,7 @@ runroot rpmkeys -Kv --define "_pkgverify_flags 0" /tmp/hello-2.0-1.x86_64.rpm

# rpmsign --addsign corrupted payload
RPMTEST_CHECK([
RPMDB_RESET
RPMKEYRING_RESET

pkg="hello-2.0-1.x86_64.rpm"
cp "${RPMTEST}"/data/RPMS/${pkg} "${RPMTEST}"/tmp/${pkg}
Expand Down Expand Up @@ -1564,10 +1569,10 @@ runroot rpmkeys --import /data/keys/*.pub
[ignore])

RPMTEST_CHECK([
# automatically signed now
runroot rpmbuild -bb --quiet \
--define "_rpmformat 6" \
/data/SPECS/attrtest.spec
runroot rpmsign --addsign /build/RPMS/noarch/attrtest-1.0-1.noarch.rpm
],
[0],
[],
Expand Down Expand Up @@ -1676,6 +1681,7 @@ RPMTEST_CLEANUP
RPMTEST_SETUP_RW([Ed25519 signatures])
AT_KEYWORDS([rpmsign signature])
RPMTEST_SKIP_IF([test x$PGP = xdummy])
echo "%_openpgp_sign gpg" >> $RPMTEST/root/.config/rpm/macros
gpg2 --import ${RPMTEST}/data/keys/*.secret
RPMTEST_CHECK([

Expand Down Expand Up @@ -1705,6 +1711,7 @@ RPMTEST_CLEANUP
RPMTEST_SETUP_RW([NIST P-256 signatures])
AT_KEYWORDS([rpmsign signature])
RPMTEST_SKIP_IF([test x$PGP = xdummy])
echo "%_openpgp_sign gpg" >> $RPMTEST/root/.config/rpm/macros
gpg2 --import ${RPMTEST}/data/keys/*.secret
RPMTEST_CHECK([
cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/
Expand Down Expand Up @@ -1733,6 +1740,7 @@ RPMTEST_CLEANUP
RPMTEST_SETUP_RW([key id collision])
AT_KEYWORDS([rpmsign signature])
RPMTEST_SKIP_IF([test x$PGP = xdummy])
echo "%_openpgp_sign gpg" >> $RPMTEST/root/.config/rpm/macros
gpg2 --import ${RPMTEST}/data/keys/keyidcollision1.asc
RPMTEST_CHECK([

Expand Down Expand Up @@ -1768,6 +1776,8 @@ RPMTEST_CLEANUP
RPMTEST_SETUP_RW([key id collision])
AT_KEYWORDS([rpmsign signature])
RPMTEST_SKIP_IF([test x$PGP = xdummy])

echo "%_openpgp_sign gpg" >> $RPMTEST/root/.config/rpm/macros
gpg2 --import ${RPMTEST}/data/keys/keyidcollision2.asc
RPMTEST_CHECK([

Expand Down Expand Up @@ -1803,6 +1813,7 @@ AT_KEYWORDS([rpmsign ima signature])
RPMTEST_SKIP_IF([$IMA_DISABLED])

cp /data/RPMS/hello-2.0-1.x86_64.rpm /tmp/
echo "%_openpgp_sign gpg" >> $RPMTEST/root/.config/rpm/macros
gpg2 --import /data/keys/rpm.org-rsa-2048-test.secret
rpmsign --key-id 4344591E1964C5FC --addsign --signfiles --fskpath=/data/keys/privkey.pem /tmp/hello-2.0-1.x86_64.rpm

Expand Down
30 changes: 28 additions & 2 deletions tests/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,36 @@ cp /data/macros.testenv @CMAKE_INSTALL_FULL_SYSCONFDIR@/rpm/
# setup an empty db that all tests are pointed to by default
rpmdb --initdb

# set up new-style XDG config directory
rpmhome=/root/.config/rpm
mkdir -p ${rpmhome}

# setup default signing id + key
sqemail="rpmbuild-user@$(uname -n)"
sqhome=${rpmhome}/sq
sqkey=$(sq key generate \
--batch \
--quiet \
--own-key \
--without-password \
--can-sign \
--cannot-authenticate \
--cannot-encrypt \
--email ${sqemail} \
2>&1 | awk '/Fingerprint/{print $2}')

cat << EOF > ${rpmhome}/macros
%_openpgp_autosign_id ${sqkey}
%_openpgp_sign sq
EOF

# import the signing key by default
sq cert export \
--cert-email "${sqemail}" > /root/rpm-key.asc
rpmkeys --import /root/rpm-key.asc

# gpg-connect-agent is very, very unhappy if this doesn't exist
mkdir -p /root/.gnupg
chmod 700 /root/.gnupg

# set up new-style XDG config directory
mkdir -p /root/.config/rpm

0 comments on commit 6798e68

Please # to comment.