From ef521ba16de3c9aae4efd12b069693a067e6731f Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Wed, 30 Oct 2024 16:46:26 +0200 Subject: [PATCH] Add support for multiple OpenPGP signatures per package, part 1/2 Add support for multiple OpenPGP header signatures per package, base64 encoded in a string array, also known as rpm v6 signatures. --addsign no longer deletes any signatures, it only creates and adds a new signature if possible. --delete and --resign behave as before: they delete ALL signatures on the package, and the latter then creates and adds a new one. For v6 packages this is the default signature type, but if requested, one v4 compat signature can be created for compatible algorithms. v6 signatures on v4 packages are also supported, but have to be explicitly requested. In that case, v3/v4 signatures are only added if none already exist and a v4 compatible algorithm is used. v3 signatures on v6 packages are not supported (out of principle, not a technical limitation) On verification, if RPMTAG_OPENPGP exists then other signature tags are ignored because they're expected to only contain compat copies of the same content. As of now, all existing signatures must validate for signature checking of a package to pass, further policies are to be added later. Fixes: #3385 --- docs/man/rpmsign.8.md | 48 ++++++++-- docs/manual/tags.md | 2 + include/rpm/rpmsign.h | 3 + include/rpm/rpmtag.h | 2 + include/rpm/rpmts.h | 3 + lib/package.cc | 1 + lib/rpmvs.cc | 46 ++++++++-- sign/rpmgensig.cc | 131 +++++++++++++++++++++------- tests/rpmgeneral.at | 1 + tests/rpmsigdig.at | 198 +++++++++++++++++++++++++++++++++++++++++- tests/rpmvfylevel.at | 1 + tools/rpmsign.cc | 12 ++- 12 files changed, 397 insertions(+), 51 deletions(-) diff --git a/docs/man/rpmsign.8.md b/docs/man/rpmsign.8.md index adff642b3f..aa8c306007 100644 --- a/docs/man/rpmsign.8.md +++ b/docs/man/rpmsign.8.md @@ -25,22 +25,25 @@ SIGNING PACKAGES: rpmsign-options --------------- -\[**\--rpmv3**\] \[**\--fskpath ***KEY*\] \[**\--signfiles**\] +\[**\--rpmv3**\] \[**\--rpmv4**\] \[**\--fskpath ***KEY*\] \[**\--signfiles**\] DESCRIPTION =========== -Both of the **\--addsign** and **\--resign** options generate and insert -new signatures for each package *PACKAGE\_FILE* given, replacing any -existing signatures. There are two options for historical reasons, there -is no difference in behavior currently. +**rpmsign** **\--addsign** generates and inserts a new OpenPGP signature +for each *PACKAGE\_FILE* given unless a signature with identical +parameters already exists, in which case no action is taken. +Arbitrary number of V6 signatures can be added. + +**rpmsign** **\--resign** generates and inserts a new OpenPGP signature +for each *PACKAGE\_FILE*, replacing any and all previous signatures. To create a signature rpmsign needs to verify the package\'s checksum. As a -result packages with a MD5/SHA1 checksums cannot be signed in FIPS mode. +result V4 packages with MD5/SHA1 checksums cannot be signed in FIPS mode. **rpmsign** **\--delsign** *PACKAGE\_FILE \...* -Delete all signatures from each package *PACKAGE\_FILE* given. +Delete all OpenPGP signatures from each package *PACKAGE\_FILE* given. **rpmsign** **\--delfilesign** *PACKAGE\_FILE \...* @@ -52,13 +55,40 @@ SIGN OPTIONS **\--rpmv3** -: Force RPM V3 header+payload signature addition. These are expensive +: Request RPM V3 header+payload signature addition on V4 packages. + These signatures are expensive and redundant baggage on packages where a separate payload digest exists (packages built with rpm \>= 4.14). Rpmsign will automatically detect the need for V3 signatures, but this option can be used to - force their creation if the packages must be fully signature + request their creation if the packages must be fully signature verifiable with rpm \< 4.14 or other interoperability reasons. + Has no effect when signing V6 packages. + +**\--rpmv4** + +: Request RPM V4 header signature addition on V6 packages. + Useful for making V6 packages signature verifiable + with rpm 4.x versions. + + V4 compatibility signatures are only ever added if the signing algorithm + is one of those known to V4: RSA, EcDSA, EdDSA (and original DSA). + Only one V4 signature can be present in a package, so this is + added only on the first **\--addsign** with a V4 compatible + algorithm, and ignored otherwise. + + Has no effect when signing V4 packages. + +**\--rpmv6** + +: Request RPM V6 header signature addition on V4 packages. + + This generally always succeeds as there can be arbitrary number of + V6 signatures on a package. A V3/V4 compatibility signatures are + added usign the same logic as **\--rpmv4** on a V6 package. + + Has no effect when signing V6 packages. + **\--fskpath ***KEY* : Used with **\--signfiles**, use file signing key *Key*. diff --git a/docs/manual/tags.md b/docs/manual/tags.md index 334e90fbbb..4880cfda41 100644 --- a/docs/manual/tags.md +++ b/docs/manual/tags.md @@ -306,6 +306,7 @@ Tag Name | Value| Type | Description ------------------|------|--------------|------------ Dsaheader | 267 | bin | OpenPGP DSA signature of the header (if thus signed) Longsigsize | 270 | int64 | Header+payload size if > 4GB. +Openpgp | 278 | string array | OpenPGP signature(s) of the header, base64 encoded Payloaddigest | 5092 | string array | Cryptographic digest of the compressed payload. Payloaddigestalgo | 5093 | int32 | ID of the payload digest algorithm. Payloaddigestalt | 5097 | string array | Cryptographic digest of the uncompressed payload. @@ -446,6 +447,7 @@ Longsigsize | Header+payload size in 64bit format Tag Name | Value| Type | Description ----------------------|------|--------------|------------ +Openpgp | 278 | string array | All OpenPGP signature(s) in the header, including legacy ones (base64 encoded) Origfilenames | 5007 | string array | Original Filenames in relocated packages. Providenevrs | 5042 | string array | Formatted `name [op version]` provide dependency strings. Conflictnevrs | 5044 | string array | Formatted `name [op version]` conflict dependency strings. diff --git a/include/rpm/rpmsign.h b/include/rpm/rpmsign.h index c876ef1bda..c0dbdab533 100644 --- a/include/rpm/rpmsign.h +++ b/include/rpm/rpmsign.h @@ -18,6 +18,9 @@ enum rpmSignFlags_e { RPMSIGN_FLAG_IMA = (1 << 0), RPMSIGN_FLAG_RPMV3 = (1 << 1), RPMSIGN_FLAG_FSVERITY = (1 << 2), + RPMSIGN_FLAG_RESIGN = (1 << 3), + RPMSIGN_FLAG_RPMV4 = (1 << 4), + RPMSIGN_FLAG_RPMV6 = (1 << 5), }; typedef rpmFlags rpmSignFlags; diff --git a/include/rpm/rpmtag.h b/include/rpm/rpmtag.h index 3a60516a30..c716bd3f43 100644 --- a/include/rpm/rpmtag.h +++ b/include/rpm/rpmtag.h @@ -68,6 +68,7 @@ typedef enum rpmTag_e { /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */ RPMTAG_VERITYSIGNATURES = RPMTAG_SIG_BASE+20, /* s[] */ RPMTAG_VERITYSIGNATUREALGO = RPMTAG_SIG_BASE+21, /* i */ + RPMTAG_OPENPGP = RPMTAG_SIG_BASE+22, /* s[] */ RPMTAG_SIG_TOP = HEADER_SIGTOP, RPMTAG_NAME = 1000, /* s */ @@ -455,6 +456,7 @@ typedef enum rpmSigTag_e { RPMSIGTAG_FILESIGNATURELENGTH = RPMTAG_SIG_BASE + 19, RPMSIGTAG_VERITYSIGNATURES = RPMTAG_VERITYSIGNATURES, RPMSIGTAG_VERITYSIGNATUREALGO = RPMTAG_VERITYSIGNATUREALGO, + RPMSIGTAG_OPENPGP = RPMTAG_OPENPGP, RPMSIGTAG_RESERVED = RPMTAG_SIG_TOP, } rpmSigTag; diff --git a/include/rpm/rpmts.h b/include/rpm/rpmts.h index dc5b31c55c..86ca62e0ef 100644 --- a/include/rpm/rpmts.h +++ b/include/rpm/rpmts.h @@ -106,6 +106,7 @@ enum rpmVSFlags_e { RPMVSF_NOSHA256HEADER = (1 << 9), RPMVSF_NODSAHEADER = (1 << 10), RPMVSF_NORSAHEADER = (1 << 11), + RPMVSF_NOOPENPGP = (1 << 12), /* bit(s) 12-15 unused */ RPMVSF_NOPAYLOAD = (1 << 16), RPMVSF_NOMD5 = (1 << 17), @@ -126,6 +127,7 @@ typedef rpmFlags rpmVSFlags; #define RPMVSF_MASK_NOSIGNATURES \ ( RPMVSF_NODSAHEADER | \ RPMVSF_NORSAHEADER | \ + RPMVSF_NOOPENPGP | \ RPMVSF_NODSA | \ RPMVSF_NORSA ) #define _RPMVSF_NOSIGNATURES RPMVSF_MASK_NOSIGNATURES @@ -133,6 +135,7 @@ typedef rpmFlags rpmVSFlags; #define RPMVSF_MASK_NOHEADER \ ( RPMVSF_NOSHA1HEADER | \ RPMVSF_NOSHA256HEADER | \ + RPMVSF_NOOPENPGP | \ RPMVSF_NODSAHEADER | \ RPMVSF_NORSAHEADER ) #define _RPMVSF_NOHEADER RPMVSF_MASK_NOHEADER diff --git a/lib/package.cc b/lib/package.cc index 83de81a93c..b16c52460f 100644 --- a/lib/package.cc +++ b/lib/package.cc @@ -58,6 +58,7 @@ static struct taglate_s { { RPMSIGTAG_RSA, RPMTAG_RSAHEADER, 0, 0 }, { RPMSIGTAG_LONGSIZE, RPMTAG_LONGSIGSIZE, 1, 0 }, { RPMSIGTAG_LONGARCHIVESIZE, RPMTAG_LONGARCHIVESIZE, 1, 0 }, + { RPMSIGTAG_OPENPGP, RPMTAG_OPENPGP, 0, 0 }, { 0 } }; diff --git a/lib/rpmvs.cc b/lib/rpmvs.cc index 53837720c4..e4909f0213 100644 --- a/lib/rpmvs.cc +++ b/lib/rpmvs.cc @@ -1,5 +1,6 @@ #include "system.h" +#include #include #include #include @@ -26,6 +27,7 @@ struct vfytag_s { }; static const struct vfytag_s rpmvfytags[] = { + { RPMTAG_OPENPGP, RPM_STRING_ARRAY_TYPE, 0, 0, }, { RPMSIGTAG_SIZE, RPM_BIN_TYPE, 0, 0, }, { RPMSIGTAG_PGP, RPM_BIN_TYPE, 0, 0, }, { RPMSIGTAG_MD5, RPM_BIN_TYPE, 0, 16, }, @@ -50,6 +52,9 @@ struct vfyinfo_s { }; static const struct vfyinfo_s rpmvfyitems[] = { + { RPMTAG_OPENPGP, 1, + { RPMSIG_SIGNATURE_TYPE, RPMVSF_NOOPENPGP, + (RPMSIG_HEADER), 0, 0, }, }, { RPMSIGTAG_SIZE, 1, { RPMSIG_OTHER_TYPE, 0, (RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, 0, }, }, @@ -131,7 +136,7 @@ int rpmIsValidHex(const char *str, size_t slen) return valid; } -static void rpmsinfoInit(const struct vfyinfo_s *vinfo, +static rpmRC rpmsinfoInit(const struct vfyinfo_s *vinfo, const struct vfytag_s *tinfo, rpmtd td, const char *origin, struct rpmsinfo_s *sinfo) @@ -139,6 +144,8 @@ static void rpmsinfoInit(const struct vfyinfo_s *vinfo, rpmRC rc = RPMRC_FAIL; const void *data = NULL; rpm_count_t dlen = 0; + uint8_t *pkt = NULL; + size_t pktlen = 0; *sinfo = vinfo->vi; /* struct assignment */ sinfo->wrapped = (vinfo->sigh == 0); @@ -193,6 +200,16 @@ static void rpmsinfoInit(const struct vfyinfo_s *vinfo, } if (sinfo->type == RPMSIG_SIGNATURE_TYPE) { + if (td->type == RPM_STRING_ARRAY_TYPE) { + if (rpmBase64Decode((const char *)data, (void **)&pkt, &pktlen)) { + rasprintf(&sinfo->msg, _("%s tag %u: invalid base64"), + origin, td->tag); + goto exit; + } + data = pkt; + dlen = pktlen; + } + char *lints = NULL; int ec = pgpPrtParams2((const uint8_t *)data, dlen, PGPTAG_SIGNATURE, &sinfo->sig, &lints); @@ -234,8 +251,10 @@ static void rpmsinfoInit(const struct vfyinfo_s *vinfo, rc = RPMRC_OK; exit: + if (pkt && pkt != td->data) + free(pkt); sinfo->rc = rc; - return; + return rc; } static void rpmsinfoFini(struct rpmsinfo_s *sinfo) @@ -291,11 +310,16 @@ const char *rpmsinfoDescr(struct rpmsinfo_s *sinfo) rangeName(sinfo->range), t); free(t); } else { - rasprintf(&sinfo->descr, _("%s OpenPGP %s%s %s"), - rangeName(sinfo->range), - pgpValString(PGPVAL_PUBKEYALGO, sinfo->sigalgo), - sinfo->alt ? " ALT" : "", - _("signature")); + if (sinfo->sigalgo) { + rasprintf(&sinfo->descr, _("%s OpenPGP %s %s"), + rangeName(sinfo->range), + pgpValString(PGPVAL_PUBKEYALGO, sinfo->sigalgo), + _("signature")); + } else { + rasprintf(&sinfo->descr, _("%s OpenPGP %s"), + rangeName(sinfo->range), + _("signature")); + } } break; } @@ -348,7 +372,13 @@ static void rpmvsAppend(struct rpmvs_s *sis, hdrblob blob, if (!rpmsinfoDisabled(&vi->vi, sis->vsflags) && rc == RPMRC_OK) { while (rpmtdNext(&td) >= 0) { - rpmsinfoInit(vi, ti, &td, o, &sis->sigs[sis->nsigs]); + if (!rpmsinfoInit(vi, ti, &td, o, &sis->sigs[sis->nsigs])) { + /* Don't bother with v3/v4 sigs when v6 sigs exist */ + if (td.tag == RPMSIGTAG_OPENPGP) { + sis->vsflags |= (RPMVSF_NODSAHEADER|RPMVSF_NORSAHEADER); + sis->vsflags |= (RPMVSF_NODSA|RPMVSF_NORSA); + } + } sis->nsigs++; } } else { diff --git a/sign/rpmgensig.cc b/sign/rpmgensig.cc index 90df052afd..85a515e3bd 100644 --- a/sign/rpmgensig.cc +++ b/sign/rpmgensig.cc @@ -17,6 +17,7 @@ #include "rpmsignfiles.hh" #endif +#include #include /* RPMSIGTAG & related */ #include #include @@ -175,11 +176,12 @@ static rpmtd makeSigTag(int ishdr, uint8_t *pkt, size_t pktlen) /* Looks sane, create the tag data */ sigtd = rpmtdNew(); + sigtd->tag = sigtag; + sigtd->flags |= RPMTD_ALLOCED; sigtd->count = pktlen; sigtd->data = memcpy(xmalloc(pktlen), pkt, pktlen);; - sigtd->type = RPM_BIN_TYPE; sigtd->tag = sigtag; - sigtd->flags |= RPMTD_ALLOCED; + sigtd->type = RPM_BIN_TYPE; exit: pgpDigParamsFree(sigp); @@ -370,6 +372,7 @@ static void deleteSigs(Header sigh) headerDel(sigh, RPMSIGTAG_DSA); headerDel(sigh, RPMSIGTAG_RSA); headerDel(sigh, RPMSIGTAG_PGP5); + headerDel(sigh, RPMSIGTAG_OPENPGP); } static void deleteFileSigs(Header sigh) @@ -380,41 +383,83 @@ static void deleteFileSigs(Header sigh) headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO); } -static int haveSignature(rpmtd sigtd, Header h) +static pgpDigParams tdParams(rpmtd td) +{ + pgpDigParams sig = NULL; + if (td->tag == RPMTAG_OPENPGP) { + uint8_t *pkt = NULL; + size_t pktlen = 0; + if (rpmBase64Decode(rpmtdGetString(td), (void **)&pkt, &pktlen) == 0) { + pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sig); + free(pkt); + } + } else { + pgpPrtParams((uint8_t *)td->data, td->count, PGPTAG_SIGNATURE, &sig); + } + return sig; +} + +static int haveSignature(rpmtd sigtd, Header sigh) { - pgpDigParams sig1 = NULL; - pgpDigParams sig2 = NULL; struct rpmtd_s oldtd; int rc = 0; /* assume no */ + rpmTagVal tag = headerIsEntry(sigh, RPMSIGTAG_RESERVED) ? + RPMTAG_OPENPGP : sigtd->tag; - if (!headerGet(h, rpmtdTag(sigtd), &oldtd, HEADERGET_DEFAULT)) + if (!headerGet(sigh, tag, &oldtd, HEADERGET_DEFAULT)) return rc; - pgpPrtParams((uint8_t *)sigtd->data, sigtd->count, PGPTAG_SIGNATURE, &sig1); + pgpDigParams newsig = tdParams(sigtd); while (rpmtdNext(&oldtd) >= 0 && rc == 0) { - pgpPrtParams((uint8_t *)oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2); - if (pgpDigParamsCmp(sig1, sig2) == 0) + pgpDigParams oldsig = tdParams(&oldtd); + if (pgpDigParamsCmp(newsig, oldsig) == 0) rc = 1; - sig2 = pgpDigParamsFree(sig2); + pgpDigParamsFree(oldsig); } - pgpDigParamsFree(sig1); + pgpDigParamsFree(newsig); rpmtdFreeData(&oldtd); return rc; } -static int putSignature(Header sigh, rpmtd sigtd) +static int putSignature(Header sigh, rpmtd sigtd, int multisig) +{ + int rc = 1; + if (multisig) { + char *b64 = rpmBase64Encode(sigtd->data, sigtd->count, 0); + char **arr = (char **)xmalloc(1 * sizeof(*arr)); + arr[0] = b64; + + rpmtd_s mtd = { + .tag = RPMSIGTAG_OPENPGP, + .type = RPM_STRING_ARRAY_TYPE, + .count = 1, + .data = arr, + .flags = RPMTD_ALLOCED|RPMTD_PTR_ALLOCED, + .ix = -1, + .size = 0, + }; + rc = (headerPut(sigh, &mtd, HEADERPUT_APPEND) == 0); + rpmtdFreeData(&mtd); + } else { + rc = (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0); + } + return rc; +} + +static int haveLegacySig(Header sigh) { - return (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0); + return headerIsEntry(sigh, RPMSIGTAG_RSA) || + headerIsEntry(sigh, RPMSIGTAG_DSA); } -static int replaceSignature(Header sigh, rpmSignFlags flags, +static int addSignature(Header sigh, rpmSignFlags flags, sigTarget sigt_v3, sigTarget sigt_v4) { int rc = -1; rpmtd sigtd = NULL; - /* Make the cheaper v4 signature first */ + /* Make a header signature */ if ((sigtd = makeGPGSignature(1, sigt_v4)) == NULL) goto exit; @@ -423,23 +468,31 @@ static int replaceSignature(Header sigh, rpmSignFlags flags, rc = 1; goto exit; } - /* Nuke all signature tags */ - deleteSigs(sigh); - if (putSignature(sigh, sigtd)) - goto exit; - - if (flags & RPMSIGN_FLAG_RPMV3) { - rpmtdFree(sigtd); - - /* Assume the same signature test holds for v3 signature too */ - if ((sigtd = makeGPGSignature(0, sigt_v3)) == NULL) + /* Add a v6 signature if requested */ + if (flags & RPMSIGN_FLAG_RPMV6) + if (putSignature(sigh, sigtd, 1)) goto exit; - if (putSignature(sigh, sigtd)) + /* Add a v4 signature if requested */ + if (flags & RPMSIGN_FLAG_RPMV4) { + if (putSignature(sigh, sigtd, 0)) goto exit; + + /* Only consider v3 signature if also adding v4 */ + if (flags & RPMSIGN_FLAG_RPMV3) { + rpmtdFree(sigtd); + + /* Assume the same signature test holds for v3 signature too */ + if ((sigtd = makeGPGSignature(0, sigt_v3)) == NULL) + goto exit; + + if (putSignature(sigh, sigtd, 0)) + goto exit; + } } + rc = 0; exit: rpmtdFree(sigtd); @@ -629,6 +682,23 @@ static int rpmSign(const char *rpm, int deleting, int flags) flags |= RPMSIGN_FLAG_RPMV3; } + /* Only v6 packages have this */ + if (headerIsEntry(sigh, RPMSIGTAG_RESERVED)) { + flags |= RPMSIGN_FLAG_RPMV6; + reserveTag = RPMSIGTAG_RESERVED; + /* v3 signatures are not welcome in v6 packages */ + if (flags & RPMSIGN_FLAG_RPMV3) { + rpmlog(RPMLOG_WARNING, + _("not generating v3 signature for v6 package: %s\n"), rpm); + flags &= ~RPMSIGN_FLAG_RPMV3; + } + } else { + flags |= RPMSIGN_FLAG_RPMV4; + /* Ensure only one legacy signature is added if adding v6 signatures */ + if ((flags & RPMSIGN_FLAG_RPMV6) && haveLegacySig(sigh)) + flags &= ~(RPMSIGN_FLAG_RPMV4|RPMSIGN_FLAG_RPMV3); + } + unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES); origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES); @@ -657,7 +727,10 @@ static int rpmSign(const char *rpm, int deleting, int flags) sigt_v4 = sigt_v3; sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES); - res = replaceSignature(sigh, flags, &sigt_v3, &sigt_v4); + if (flags & RPMSIGN_FLAG_RESIGN) + deleteSigs(sigh); + + res = addSignature(sigh, flags, &sigt_v3, &sigt_v4); if (res != 0) { if (res == 1) { rpmlog(RPMLOG_WARNING, @@ -671,10 +744,6 @@ static int rpmSign(const char *rpm, int deleting, int flags) res = -1; } - /* Only v6 packages have this */ - if (headerIsEntry(h, RPMSIGTAG_RESERVED)) - reserveTag = RPMSIGTAG_RESERVED; - /* Adjust reserved size for added/removed signatures */ if (headerGet(sigh, reserveTag, &utd, HEADERGET_MINMEM)) { int diff = headerSizeof(sigh, HEADER_MAGIC_YES) - origSigSize; diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at index b31e322cd3..2c7f2c217b 100644 --- a/tests/rpmgeneral.at +++ b/tests/rpmgeneral.at @@ -191,6 +191,7 @@ OLDSUGGESTS OLDSUGGESTSFLAGS OLDSUGGESTSNAME OLDSUGGESTSVERSION +OPENPGP OPTFLAGS ORDERFLAGS ORDERNAME diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at index 6e94973b46..4ef1e8165a 100644 --- a/tests/rpmsigdig.at +++ b/tests/rpmsigdig.at @@ -641,6 +641,7 @@ runroot rpmkeys --define '_pkgverify_level all' -Kv --nosignature /data/RPMS/hel [[Checking package before importing key: /data/RPMS/hello-2.0-1.x86_64-signed-with-subkey.rpm: Header OpenPGP V4 RSA/SHA512 signature, key ID 1f71177215217ee0: NOKEY + Header OpenPGP signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Header SHA256 digest: OK Payload SHA256 digest: OK @@ -699,6 +700,7 @@ runroot rpmkeys --define '_pkgverify_level all' -Kv --nosignature /data/RPMS/hel [Checking package before importing key: /data/RPMS/hello-2.0-1.x86_64-signed-with-subkey.rpm: Header OpenPGP V4 RSA/SHA512 signature, key ID 1f71177215217ee0: NOKEY + Header OpenPGP signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Header SHA256 digest: OK Payload SHA256 digest: OK @@ -717,6 +719,7 @@ RPMOUTPUT_SEQUOIA([ Key 1F71177215217EE0 invalid: key is not alive])dnl RPMOUTPUT_SEQUOIA([ because: The subkey is not live])dnl RPMOUTPUT_SEQUOIA([ because: Expired on 2022-04-12T00:00:15Z])dnl Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: b6542f92f30650c36b6f41bcb3a771bfeb04e625: NOTTRUSTED + Header OpenPGP signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Header SHA256 digest: OK Payload SHA256 digest: OK @@ -731,6 +734,7 @@ RPMOUTPUT_SEQUOIA([ Key 1F71177215217EE0 invalid: key is not alive])dnl RPMOUTPUT_SEQUOIA([ because: The subkey is not live])dnl RPMOUTPUT_SEQUOIA([ because: Expired on 2022-04-12T00:00:15Z])dnl Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: b6542f92f30650c36b6f41bcb3a771bfeb04e625: NOTTRUSTED + Header OpenPGP signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Legacy OpenPGP RSA signature: NOTFOUND Legacy OpenPGP DSA signature: NOTFOUND @@ -769,6 +773,7 @@ runroot rpmkeys --define '_pkgverify_level all' -Kv --nosignature /data/RPMS/hel [Checking package before importing key: /data/RPMS/hello-2.0-1.x86_64-signed-with-subkey.rpm: Header OpenPGP V4 RSA/SHA512 signature, key ID 1f71177215217ee0: NOKEY + Header OpenPGP signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Header SHA256 digest: OK Payload SHA256 digest: OK @@ -785,6 +790,7 @@ RPMOUTPUT_LEGACY([error: Subkey 1f71177215217ee0 of key b3a771bfeb04e625 (Alice RPMOUTPUT_SEQUOIA([error: Verifying a signature using certificate B6542F92F30650C36B6F41BCB3A771BFEB04E625 (Alice ):])dnl RPMOUTPUT_SEQUOIA([ Key 1F71177215217EE0 is invalid: key is revoked])dnl Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: b6542f92f30650c36b6f41bcb3a771bfeb04e625: NOTTRUSTED + Header OpenPGP signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Header SHA256 digest: OK Payload SHA256 digest: OK @@ -797,6 +803,7 @@ RPMOUTPUT_LEGACY([error: Subkey 1f71177215217ee0 of key b3a771bfeb04e625 (Alice RPMOUTPUT_SEQUOIA([error: Verifying a signature using certificate B6542F92F30650C36B6F41BCB3A771BFEB04E625 (Alice ):])dnl RPMOUTPUT_SEQUOIA([ Key 1F71177215217EE0 is invalid: key is revoked])dnl Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: b6542f92f30650c36b6f41bcb3a771bfeb04e625: NOTTRUSTED + Header OpenPGP signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Legacy OpenPGP RSA signature: NOTFOUND Legacy OpenPGP DSA signature: NOTFOUND @@ -1387,7 +1394,7 @@ AT_SKIP_IF([test x$PGP = xdummy]) RPMDB_INIT RPMTEST_CHECK([ -cat << EOF > ${HOME}/.rpmmacros +cat << EOF >> ${HOME}/.rpmmacros %_openpgp_sign sq %_openpgp_sign_id 771B18D3D7BAA28734333C424344591E1964C5FC EOF @@ -1441,6 +1448,195 @@ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm [ignore]) RPMTEST_CLEANUP +AT_SETUP([rpmsign --addsign multisig v4]) +AT_KEYWORDS([rpmsign signature multisig v4]) +AT_SKIP_IF([test x$PGP = xdummy]) +RPMDB_INIT + +RPMTEST_CHECK([ +cat << EOF >> ${HOME}/.rpmmacros +%_openpgp_sign sq +%_openpgp_sign_id 771B18D3D7BAA28734333C424344591E1964C5FC +EOF + +runroot_other sq key import /data/keys/*.secret +runroot rpmkeys --import /data/keys/*.pub +], +[0], +[ignore], +[ignore]) + +RPMTEST_CHECK([ +cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/ +runroot rpmsign --addsign --rpmv6 /tmp/hello-2.0-1.x86_64.rpm &> /dev/null +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm +], +[0], +[/tmp/hello-2.0-1.x86_64.rpm: + Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK + Header SHA256 digest: OK + Payload SHA256 digest: OK +], +[]) + +RPMTEST_CHECK([ +# resigning with identical key shouldn't add anything +runroot rpmsign --addsign --rpmv6 /tmp/hello-2.0-1.x86_64.rpm &> /dev/null +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm +], +[0], +[/tmp/hello-2.0-1.x86_64.rpm: + Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK + Header SHA256 digest: OK + Payload SHA256 digest: OK +], +[]) + +RPMTEST_CHECK([ +runroot rpmsign --addsign --rpmv6 --key-id 152BB32FD9CA982797E835CFB0645AEC757BF69E /tmp/hello-2.0-1.x86_64.rpm &> /dev/null +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm +], +[0], +[/tmp/hello-2.0-1.x86_64.rpm: + Header OpenPGP V4 EdDSA/SHA512 signature, key fingerprint: 152bb32fd9ca982797e835cfb0645aec757bf69e: OK + Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK + Header SHA256 digest: OK + Payload SHA256 digest: OK +], +[]) + +RPMTEST_CHECK([ +runroot rpmsign --addsign --rpmv6 --key-id E8A62C0512B06B5D2183BA207F1C21F95F65BBE8 /tmp/hello-2.0-1.x86_64.rpm &> /dev/null +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm +], +[0], +[/tmp/hello-2.0-1.x86_64.rpm: + Header OpenPGP V4 ECDSA/SHA512 signature, key fingerprint: e8a62c0512b06b5d2183ba207f1c21f95f65bbe8: OK + Header OpenPGP V4 EdDSA/SHA512 signature, key fingerprint: 152bb32fd9ca982797e835cfb0645aec757bf69e: OK + Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK + Header SHA256 digest: OK + Payload SHA256 digest: OK +], +[]) + +RPMTEST_CHECK([ +runroot rpmkeys --delete 152bb32fd9ca982797e835cfb0645aec757bf69e +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm +], +[1], +[/tmp/hello-2.0-1.x86_64.rpm: + Header OpenPGP V4 ECDSA/SHA512 signature, key fingerprint: e8a62c0512b06b5d2183ba207f1c21f95f65bbe8: OK + Header OpenPGP V4 EdDSA/SHA512 signature, key ID b0645aec757bf69e: NOKEY + Header OpenPGP V4 RSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK + Header SHA256 digest: OK + Payload SHA256 digest: OK +], +[]) + +RPMTEST_CHECK([ +runroot rpmsign --resign --key-id E8A62C0512B06B5D2183BA207F1C21F95F65BBE8 /tmp/hello-2.0-1.x86_64.rpm &> /dev/null +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm +], +[0], +[/tmp/hello-2.0-1.x86_64.rpm: + Header OpenPGP V4 ECDSA/SHA512 signature, key fingerprint: e8a62c0512b06b5d2183ba207f1c21f95f65bbe8: OK + Header SHA256 digest: OK + Payload SHA256 digest: OK +], +[]) + +RPMTEST_CHECK([ +runroot rpmsign --delsign /tmp/hello-2.0-1.x86_64.rpm &> /dev/null +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm +], +[0], +[/tmp/hello-2.0-1.x86_64.rpm: + Header SHA256 digest: OK + Payload SHA256 digest: OK +], +[]) + +RPMTEST_CLEANUP + +AT_SETUP([rpmsign --addsign multisig v6]) +AT_KEYWORDS([rpmsign signature multisig v6]) +AT_SKIP_IF([test x$PGP = xdummy]) +RPMDB_INIT + +RPMTEST_CHECK([ +cat << EOF >> ${HOME}/.rpmmacros +%_openpgp_sign sq +%_openpgp_sign_id 771B18D3D7BAA28734333C424344591E1964C5FC +EOF + +runroot_other sq key import /data/keys/*.secret +runroot rpmkeys --import /data/keys/*.pub +], +[0], +[ignore], +[ignore]) + +RPMTEST_CHECK([ +runroot rpmbuild -bb --quiet \ + --define "_rpmfilever 6" \ + /data/SPECS/attrtest.spec +runroot rpmsign --addsign /build/RPMS/noarch/attrtest-1.0-1.noarch.rpm +], +[0], +[], +[ignore]) + +RPMTEST_CHECK([ +runroot rpmkeys -K /build/RPMS/noarch/attrtest-1.0-1.noarch.rpm +], +[0], +[/build/RPMS/noarch/attrtest-1.0-1.noarch.rpm: digests signatures OK +], +[]) + +RPMTEST_CHECK([ +for t in DSAHEADER RSAHEADER SIGGPG SIGPGP OPENPGP; do + runroot rpm -qp --qf "$t: %{$t}\n" /build/RPMS/noarch/attrtest-1.0-1.noarch.rpm | grep \(none\) +done +], +[ignore], +[DSAHEADER: (none) +RSAHEADER: (none) +SIGGPG: (none) +SIGPGP: (none) +], +[]) + +RPMTEST_CHECK([ +runroot rpmsign --resign --rpmv4 \ + --key-id E8A62C0512B06B5D2183BA207F1C21F95F65BBE8 \ + /build/RPMS/noarch/attrtest-1.0-1.noarch.rpm +], +[0], +[], +[ignore]) + +RPMTEST_CHECK([ +runroot rpmkeys -K /build/RPMS/noarch/attrtest-1.0-1.noarch.rpm +], +[0], +[/build/RPMS/noarch/attrtest-1.0-1.noarch.rpm: digests signatures OK +], +[]) + +RPMTEST_CHECK([ +for t in DSAHEADER RSAHEADER SIGGPG SIGPGP OPENPGP; do + runroot rpm -qp --qf "$t: %{$t}\n" /build/RPMS/noarch/attrtest-1.0-1.noarch.rpm | grep \(none\) +done +], +[ignore], +[RSAHEADER: (none) +SIGGPG: (none) +SIGPGP: (none) +], +[]) +RPMTEST_CLEANUP + # ------------------------------ # Test --delsign AT_SETUP([rpmsign --delsign]) diff --git a/tests/rpmvfylevel.at b/tests/rpmvfylevel.at index 3562d96dce..f34713153a 100644 --- a/tests/rpmvfylevel.at +++ b/tests/rpmvfylevel.at @@ -346,6 +346,7 @@ nohdrs 0 nosig /data/RPMS/hello-2.0-1.x86_64-signed.rpm: + Header OpenPGP signature: NOTFOUND Header OpenPGP RSA signature: NOTFOUND Header OpenPGP DSA signature: NOTFOUND Header SHA256 digest: OK diff --git a/tools/rpmsign.cc b/tools/rpmsign.cc index 16063991a3..006fb2d478 100644 --- a/tools/rpmsign.cc +++ b/tools/rpmsign.cc @@ -43,7 +43,13 @@ static struct poptOption signOptsTable[] = { #endif { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &sargs.signflags, RPMSIGN_FLAG_RPMV3, - N_("create rpm v3 header+payload signatures") }, + N_("request legacy rpm v3 header+payload signatures on v4 packages") }, + { "rpmv4", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), + &sargs.signflags, RPMSIGN_FLAG_RPMV4, + N_("request legacy rpm v4 header signatures on v6 packages") }, + { "rpmv6", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), + &sargs.signflags, RPMSIGN_FLAG_RPMV6, + N_("request rpm v6 header signature on v4 packages") }, #ifdef WITH_IMAEVM { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &sargs.signflags, RPMSIGN_FLAG_IMA, @@ -207,8 +213,10 @@ int main(int argc, char *argv[]) #endif switch (mode) { - case MODE_ADDSIGN: case MODE_RESIGN: + sargs.signflags |= RPMSIGN_FLAG_RESIGN; + /* fallthrough */ + case MODE_ADDSIGN: ec = doSign(optCon, &sargs); break; case MODE_DELSIGN: