From 8454cdf94484d099015cf67579f253968d82c8f7 Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Mon, 18 Nov 2024 15:50:06 +0200 Subject: [PATCH] Add support for multiple OpenPGP signatures per package, part 2/2 Add a tag extension for RPMTAG_OPENPGP (on top of the concrete tag) to handle compatibility with v3/v4 signatures: the extension collects all legacy signatures under the same umbrella so users don't need to query multiple different tags, you just query for RPMTAG_OPENPGP to get all them at once. Extend :pgpsig tag format to handle the new string array/base64 variant. Update --info/-i query to use the extension and output all existing signatures, one per line. The no-signature case of "Signature : (none)" is preserved as-is to help backwards compatibility with scripts parsing the output. Related: #3385 --- lib/formats.cc | 24 +++++++++++++++++++++--- lib/tagexts.cc | 34 ++++++++++++++++++++++++++++++++++ rpmpopt.in | 2 +- tests/rpmquery.at | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/lib/formats.cc b/lib/formats.cc index 61d04fe65e..a5e891d1ab 100644 --- a/lib/formats.cc +++ b/lib/formats.cc @@ -419,12 +419,12 @@ static char *jsonFormat(rpmtd td, char **emsg) } /* signature fingerprint and time formatting */ -static char * pgpsigFormat(rpmtd td, char **emsg) +static char * pgpsigFormatOne(uint8_t *pkt, size_t pktlen, char **emsg) { char * val = NULL; pgpDigParams sigp = NULL; - if (pgpPrtParams((uint8_t*)td->data, td->count, PGPTAG_SIGNATURE, &sigp)) { + if (pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sigp)) { *emsg = xstrdup(_("(not an OpenPGP signature)")); } else { char dbuf[BUFSIZ]; @@ -451,6 +451,24 @@ static char * pgpsigFormat(rpmtd td, char **emsg) return val; } +static char * pgpsigFormat(rpmtd td, char **emsg) +{ + char *val = NULL; + if (rpmtdType(td) == RPM_BIN_TYPE) { + val = pgpsigFormatOne((uint8_t *)td->data, td->count, emsg); + } else if (rpmtdType(td) == RPM_STRING_ARRAY_TYPE) { + uint8_t *pkt = NULL; + size_t pktlen = 0; + if (rpmBase64Decode(rpmtdGetString(td), (void **)&pkt, &pktlen) == 0) { + val = pgpsigFormatOne(pkt, pktlen, emsg); + free(pkt); + } + } else { + *emsg = xstrdup(_("(invalid type)")); + } + return val; +} + /* dependency flags formatting */ static char * depflagsFormat(rpmtd td, char **emsg) { @@ -581,7 +599,7 @@ static const struct headerFmt_s rpmHeaderFormats[] = { { RPMTD_FORMAT_BASE64, "base64", RPM_BINARY_CLASS, base64Format }, { RPMTD_FORMAT_PGPSIG, "pgpsig", - RPM_BINARY_CLASS, pgpsigFormat }, + RPM_NULL_CLASS, pgpsigFormat }, { RPMTD_FORMAT_DEPFLAGS, "depflags", RPM_NUMERIC_CLASS, depflagsFormat }, { RPMTD_FORMAT_DEPTYPE, "deptype", diff --git a/lib/tagexts.cc b/lib/tagexts.cc index ed2f678964..9f8386ffda 100644 --- a/lib/tagexts.cc +++ b/lib/tagexts.cc @@ -1052,6 +1052,39 @@ static int sysusersTag(Header h, rpmtd td, headerGetFlags hgflags) return (td->count > 0); } +static void trySigTag(Header h, rpmTagVal tag, ARGV_t *sigs) +{ + struct rpmtd_s td; + if (headerGet(h, tag, &td, HEADERGET_ALLOC)) { + char *b64 = rpmBase64Encode((uint8_t *)td.data, td.count, 0); + if (b64) { + argvAdd(sigs, b64); + free(b64); + } + rpmtdFreeData(&td); + } +} + +static int openpgpTag(Header h, rpmtd td, headerGetFlags hgflags) +{ + if (headerGet(h, RPMTAG_OPENPGP, td, HEADERGET_ALLOC)) + return 1; + + ARGV_t sigs = NULL; + trySigTag(h, RPMTAG_RSAHEADER, &sigs); + trySigTag(h, RPMTAG_DSAHEADER, &sigs); + trySigTag(h, RPMTAG_SIGPGP, &sigs); + trySigTag(h, RPMTAG_SIGGPG, &sigs); + + if (sigs) { + td->data = sigs; + td->count = argvCount(sigs); + td->type = RPM_STRING_ARRAY_TYPE; + td->flags = RPMTD_ALLOCED|RPMTD_PTR_ALLOCED; + } + return td->count != 0; +} + static const struct headerTagFunc_s rpmHeaderTagExtensions[] = { { RPMTAG_GROUP, groupTag }, { RPMTAG_DESCRIPTION, descriptionTag }, @@ -1093,6 +1126,7 @@ static const struct headerTagFunc_s rpmHeaderTagExtensions[] = { { RPMTAG_FILENLINKS, filenlinksTag }, { RPMTAG_SYSUSERS, sysusersTag }, { RPMTAG_FILEMIMES, filemimesTag }, + { RPMTAG_OPENPGP, openpgpTag }, { 0, NULL } }; diff --git a/rpmpopt.in b/rpmpopt.in index 40a173324f..259b187e40 100644 --- a/rpmpopt.in +++ b/rpmpopt.in @@ -96,7 +96,7 @@ Install Date: %|INSTALLTIME?{%{INSTALLTIME:date}}:{(not installed)}|\n\ Group : %{GROUP}\n\ Size : %{LONGSIZE}\n\ %|LICENSE?{License : %{LICENSE}}|\n\ -Signature : %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\n\ +Signature :%|OPENPGP?{[\n %{OPENPGP:pgpsig}]}:{ (none)}|\n\ Source RPM : %{SOURCERPM}\n\ Build Date : %{BUILDTIME:date}\n\ Build Host : %{BUILDHOST}\n\ diff --git a/tests/rpmquery.at b/tests/rpmquery.at index 33c5708bc9..1f20bac9e5 100644 --- a/tests/rpmquery.at +++ b/tests/rpmquery.at @@ -420,6 +420,18 @@ rpm \ [RSA/SHA256, Thu Apr 6 13:02:33 2017, Key ID 4344591e1964c5fc], [warning: /data/RPMS/hello-2.0-1.x86_64-signed.rpm: Header OpenPGP V4 RSA/SHA256 signature, key ID 4344591e1964c5fc: NOKEY ]) + +RPMTEST_CHECK([[ +runroot rpm \ + --nosignature \ + --qf "[%{openpgp:pgpsig}\n]" \ + -qp /data/RPMS/hello-2.0-1.x86_64-signed.rpm +]], +[0], +[RSA/SHA256, Thu Apr 6 13:02:33 2017, Key ID 4344591e1964c5fc +RSA/SHA256, Thu Apr 6 13:02:32 2017, Key ID 4344591e1964c5fc +], +[]) RPMTEST_CLEANUP # ------------------------------ @@ -1396,3 +1408,32 @@ runroot rpm -qp --filemime /build/RPMS/noarch/filetypes-1.0-1.noarch.rpm | sed - ], []) RPMTEST_CLEANUP + +AT_SETUP([info query output]) +AT_KEYWORDS([query signature]) +RPMTEST_CHECK([ +runroot rpm -qi --nosignature /data/RPMS/hello-2.0-1.x86_64-signed.rpm +], +[0], +[[Name : hello +Version : 2.0 +Release : 1 +Architecture: x86_64 +Install Date: (not installed) +Group : Testing +Size : 7243 +License : GPL +Signature : + RSA/SHA256, Thu Apr 6 13:02:33 2017, Key ID 4344591e1964c5fc + RSA/SHA256, Thu Apr 6 13:02:32 2017, Key ID 4344591e1964c5fc +Source RPM : hello-2.0-1.src.rpm +Build Date : Sat Nov 22 12:00:00 2008 +Build Host : localhost +Relocations : /usr +Summary : hello -- hello, world rpm +Description : +Simple rpm demonstration. +]], +[]) +RPMTEST_CLEANUP +