From 6798e6832ec6ef36a1a2fb6e4e5af37bf83263d9 Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Thu, 14 Nov 2024 13:34:53 +0200 Subject: [PATCH] Support automatic signing on build when _openpgp_autosign_id is set 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: #2678 --- build/pack.cc | 32 ++++++++++++++++++++++++++++++++ tests/data/macros.testenv | 1 + tests/local.at | 4 ++++ tests/pinned/common/buildrepr.sh | 1 + tests/rpmquery.at | 2 +- tests/rpmsigdig.at | 29 ++++++++++++++++++++--------- tests/setup.sh | 30 ++++++++++++++++++++++++++++-- 7 files changed, 87 insertions(+), 12 deletions(-) diff --git a/build/pack.cc b/build/pack.cc index 9c87ed7143..bbcd28856f 100644 --- a/build/pack.cc +++ b/build/pack.cc @@ -15,12 +15,14 @@ #include /* RPMSIGTAG*, rpmReadPackageFile */ #include #include +#include #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" @@ -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(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) { @@ -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; } @@ -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; diff --git a/tests/data/macros.testenv b/tests/data/macros.testenv index 205bd1be3a..7c52461638 100644 --- a/tests/data/macros.testenv +++ b/tests/data/macros.testenv @@ -4,3 +4,4 @@ %_tmppath %{getenv:RPMTEST}/var/tmp %_dbpath /var/lib/rpm-testsuite %_keyring openpgp +%_keyringpath /var/lib/rpm-keyring diff --git a/tests/local.at b/tests/local.at index 2d28e3e2b8..750d1aada7 100644 --- a/tests/local.at +++ b/tests/local.at @@ -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 diff --git a/tests/pinned/common/buildrepr.sh b/tests/pinned/common/buildrepr.sh index 6e624a5dd1..4f00d17dc8 100644 --- a/tests/pinned/common/buildrepr.sh +++ b/tests/pinned/common/buildrepr.sh @@ -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 diff --git a/tests/rpmquery.at b/tests/rpmquery.at index 44600d10e5..4f36990730 100644 --- a/tests/rpmquery.at +++ b/tests/rpmquery.at @@ -1172,7 +1172,7 @@ import json s = open('stdout').read() print(len(json.loads(s))) ], -[58 +[59 ], []) RPMTEST_CLEANUP diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at index dc62652e21..fd2d1f0954 100644 --- a/tests/rpmsigdig.at +++ b/tests/rpmsigdig.at @@ -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 @@ -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 @@ -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 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 @@ -1246,7 +1251,7 @@ POST-DELSIGN # rpmsign --addsign 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 @@ -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" @@ -1309,7 +1314,7 @@ error: /gnus/not/here exec failed (1) # rpmsign --addsign 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" @@ -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} @@ -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} @@ -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], [], @@ -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([ @@ -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/ @@ -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([ @@ -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([ @@ -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 diff --git a/tests/setup.sh b/tests/setup.sh index 60771d6b6b..fd6c8e7ae8 100755 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -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