Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for multiple signatures per package, aka v6 signatures #3439

Merged
merged 6 commits into from
Nov 19, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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
pmatilai committed Nov 18, 2024
commit ebd388477c419a38c05079295bf15bd68bcecdf3
48 changes: 39 additions & 9 deletions docs/man/rpmsign.8.md
Original file line number Diff line number Diff line change
@@ -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*.
2 changes: 2 additions & 0 deletions docs/manual/tags.md
Original file line number Diff line number Diff line change
@@ -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.
3 changes: 3 additions & 0 deletions include/rpm/rpmsign.h
Original file line number Diff line number Diff line change
@@ -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;

2 changes: 2 additions & 0 deletions include/rpm/rpmtag.h
Original file line number Diff line number Diff line change
@@ -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;

3 changes: 3 additions & 0 deletions include/rpm/rpmts.h
Original file line number Diff line number Diff line change
@@ -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,13 +127,15 @@ typedef rpmFlags rpmVSFlags;
#define RPMVSF_MASK_NOSIGNATURES \
( RPMVSF_NODSAHEADER | \
RPMVSF_NORSAHEADER | \
RPMVSF_NOOPENPGP | \
RPMVSF_NODSA | \
RPMVSF_NORSA )
#define _RPMVSF_NOSIGNATURES RPMVSF_MASK_NOSIGNATURES

#define RPMVSF_MASK_NOHEADER \
( RPMVSF_NOSHA1HEADER | \
RPMVSF_NOSHA256HEADER | \
RPMVSF_NOOPENPGP | \
RPMVSF_NODSAHEADER | \
RPMVSF_NORSAHEADER )
#define _RPMVSF_NOHEADER RPMVSF_MASK_NOHEADER
1 change: 1 addition & 0 deletions lib/package.cc
Original file line number Diff line number Diff line change
@@ -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 }
};

46 changes: 38 additions & 8 deletions lib/rpmvs.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "system.h"

#include <rpm/rpmbase64.h>
#include <rpm/rpmkeyring.h>
#include <rpm/rpmmacro.h>
#include <rpm/rpmlog.h>
@@ -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,14 +136,16 @@ 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)
{
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 {
Loading