2017-04-28 15:32:24 +08:00
|
|
|
#include "system.h"
|
|
|
|
|
2018-05-08 19:21:53 +08:00
|
|
|
#include <pthread.h>
|
2017-04-28 15:32:24 +08:00
|
|
|
#include <rpm/rpmkeyring.h>
|
2018-05-08 19:21:53 +08:00
|
|
|
#include <rpm/rpmmacro.h>
|
|
|
|
#include <rpm/rpmlog.h>
|
2017-04-28 15:32:24 +08:00
|
|
|
#include "lib/rpmvs.h"
|
|
|
|
#include "rpmio/digest.h"
|
|
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
struct rpmvs_s {
|
|
|
|
struct rpmsinfo_s *sigs;
|
|
|
|
int nsigs;
|
2017-05-22 17:32:32 +08:00
|
|
|
int nalloced;
|
2018-04-05 19:10:37 +08:00
|
|
|
rpmVSFlags vsflags;
|
2018-04-06 19:12:48 +08:00
|
|
|
rpmDigestBundle bundle;
|
2018-04-06 19:17:25 +08:00
|
|
|
rpmKeyring keyring;
|
2018-06-27 16:22:41 +08:00
|
|
|
int vfylevel;
|
2017-04-28 15:32:24 +08:00
|
|
|
};
|
|
|
|
|
2017-05-11 15:40:28 +08:00
|
|
|
struct vfytag_s {
|
|
|
|
rpmTagVal tag;
|
|
|
|
rpmTagType tagtype;
|
|
|
|
rpm_count_t tagcount;
|
|
|
|
rpm_count_t tagsize;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct vfytag_s rpmvfytags[] = {
|
|
|
|
{ RPMSIGTAG_SIZE, RPM_BIN_TYPE, 0, 0, },
|
|
|
|
{ RPMSIGTAG_PGP, RPM_BIN_TYPE, 0, 0, },
|
|
|
|
{ RPMSIGTAG_MD5, RPM_BIN_TYPE, 0, 16, },
|
|
|
|
{ RPMSIGTAG_GPG, RPM_BIN_TYPE, 0, 0, },
|
|
|
|
{ RPMSIGTAG_PAYLOADSIZE, RPM_INT32_TYPE, 1, 4, },
|
|
|
|
{ RPMSIGTAG_RESERVEDSPACE, RPM_BIN_TYPE, 0, 0, },
|
|
|
|
{ RPMTAG_DSAHEADER, RPM_BIN_TYPE, 0, 0, },
|
|
|
|
{ RPMTAG_RSAHEADER, RPM_BIN_TYPE, 0, 0, },
|
|
|
|
{ RPMTAG_SHA1HEADER, RPM_STRING_TYPE, 1, 41, },
|
|
|
|
{ RPMSIGTAG_LONGSIZE, RPM_INT64_TYPE, 1, 8, },
|
|
|
|
{ RPMSIGTAG_LONGARCHIVESIZE, RPM_INT64_TYPE, 1, 8, },
|
|
|
|
{ RPMTAG_SHA256HEADER, RPM_STRING_TYPE, 1, 65, },
|
|
|
|
{ RPMTAG_PAYLOADDIGEST, RPM_STRING_ARRAY_TYPE, 0, 0, },
|
2019-10-03 19:58:11 +08:00
|
|
|
{ RPMTAG_PAYLOADDIGESTALT, RPM_STRING_ARRAY_TYPE, 0, 0, },
|
2017-05-11 15:40:28 +08:00
|
|
|
{ 0 } /* sentinel */
|
|
|
|
};
|
|
|
|
|
2017-05-15 16:44:47 +08:00
|
|
|
struct vfyinfo_s {
|
|
|
|
rpmTagVal tag;
|
2018-04-13 18:35:25 +08:00
|
|
|
int sigh;
|
2017-05-15 16:44:47 +08:00
|
|
|
struct rpmsinfo_s vi;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct vfyinfo_s rpmvfyitems[] = {
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_SIZE, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_OTHER_TYPE, 0,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, 0, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_PGP, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSA,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, PGPPUBKEYALGO_RSA, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_MD5, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_DIGEST_TYPE, RPMVSF_NOMD5,
|
|
|
|
(RPMSIG_HEADER|RPMSIG_PAYLOAD), PGPHASHALGO_MD5, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_GPG, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_SIGNATURE_TYPE, RPMVSF_NODSA,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, PGPPUBKEYALGO_DSA, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_PAYLOADSIZE, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_OTHER_TYPE, 0,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_PAYLOAD), 0, 0, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_RESERVEDSPACE, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_OTHER_TYPE, 0,
|
2018-04-13 20:08:09 +08:00
|
|
|
0, 0, 0, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMTAG_DSAHEADER, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_SIGNATURE_TYPE, RPMVSF_NODSAHEADER,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER), 0, PGPPUBKEYALGO_DSA, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMTAG_RSAHEADER, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_SIGNATURE_TYPE, RPMVSF_NORSAHEADER,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER), 0, PGPPUBKEYALGO_RSA, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMTAG_SHA1HEADER, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_DIGEST_TYPE, RPMVSF_NOSHA1HEADER,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER), PGPHASHALGO_SHA1, 0, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_LONGSIZE, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_OTHER_TYPE, 0,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, 0, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMSIGTAG_LONGARCHIVESIZE, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_OTHER_TYPE, 0,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, 0, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMTAG_SHA256HEADER, 1,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_DIGEST_TYPE, RPMVSF_NOSHA256HEADER,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_HEADER), PGPHASHALGO_SHA256, 0, }, },
|
2018-04-13 18:35:25 +08:00
|
|
|
{ RPMTAG_PAYLOADDIGEST, 0,
|
2017-05-15 16:44:47 +08:00
|
|
|
{ RPMSIG_DIGEST_TYPE, RPMVSF_NOPAYLOAD,
|
2018-04-13 20:08:09 +08:00
|
|
|
(RPMSIG_PAYLOAD), PGPHASHALGO_SHA256, 0, }, },
|
2019-10-03 19:58:11 +08:00
|
|
|
{ RPMTAG_PAYLOADDIGESTALT, 0,
|
|
|
|
{ RPMSIG_DIGEST_TYPE, RPMVSF_NOPAYLOAD,
|
|
|
|
(RPMSIG_PAYLOAD), PGPHASHALGO_SHA256, 0, 1, }, },
|
2017-04-28 15:32:24 +08:00
|
|
|
{ 0 } /* sentinel */
|
|
|
|
};
|
|
|
|
|
2017-05-24 16:20:35 +08:00
|
|
|
static const char *rangeName(int range);
|
2017-05-24 17:17:46 +08:00
|
|
|
static const char * rpmSigString(rpmRC res);
|
2018-04-10 16:24:19 +08:00
|
|
|
static void rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo);
|
2017-05-12 18:05:20 +08:00
|
|
|
|
2017-05-11 15:18:00 +08:00
|
|
|
static int sinfoLookup(rpmTagVal tag)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
2017-05-15 16:44:47 +08:00
|
|
|
const struct vfyinfo_s *start = &rpmvfyitems[0];
|
2017-05-11 15:18:00 +08:00
|
|
|
int ix = -1;
|
2017-05-15 16:44:47 +08:00
|
|
|
for (const struct vfyinfo_s *si = start; si->tag; si++) {
|
2017-04-28 15:32:24 +08:00
|
|
|
if (tag == si->tag) {
|
2017-05-11 15:18:00 +08:00
|
|
|
ix = si - start;
|
2017-04-28 15:32:24 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-05-11 15:18:00 +08:00
|
|
|
return ix;
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
|
2017-05-30 15:16:05 +08:00
|
|
|
static int validHex(const char *str, size_t slen)
|
|
|
|
{
|
|
|
|
int valid = 0; /* Assume invalid */
|
|
|
|
const char *b;
|
|
|
|
|
|
|
|
/* Our hex data is always even sized and at least sha-1 long */
|
|
|
|
if (slen % 2 || slen < 40)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
for (b = str ; *b != '\0'; b++) {
|
|
|
|
if (strchr("0123456789abcdefABCDEF", *b) == NULL)
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
valid = 1;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
2018-04-05 19:46:36 +08:00
|
|
|
static void rpmsinfoInit(const struct vfyinfo_s *vinfo,
|
2018-04-05 18:58:44 +08:00
|
|
|
const struct vfytag_s *tinfo,
|
|
|
|
rpmtd td, const char *origin,
|
2018-04-05 19:46:36 +08:00
|
|
|
struct rpmsinfo_s *sinfo)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
rpmRC rc = RPMRC_FAIL;
|
|
|
|
const void *data = NULL;
|
|
|
|
rpm_count_t dlen = 0;
|
|
|
|
|
2018-04-05 18:58:44 +08:00
|
|
|
*sinfo = vinfo->vi; /* struct assignment */
|
Implement configurable, mandatory signature/digest verify level for rpm -K
Traditionally rpm has verified whatever digests and signatures are present
(unless disabled) but there hasn't been any way to *require* either type
of verification, and making it all too easy to fool rpm into accepting
a tampered package whose signatures and digests have just been stripped
off and content modified. This commit adds support for required
verification level, possible levels being "none" (for traditional behavior
and default for now), "digest", "signature" and "all" (for both signatures
and digests).
What it means is that the specified level of validation is required for
the entire package file: eg on digest level, both the header and the
payload must have been validated with a digest. All digest algorithms are
considered equal for this purpose to abstract out version differences:
eg all valid rpm packages have *some* digest covering the entire package.
Traditionally the only digest covering the payload is the md5sum, but
packages built with rpm >= 4.14.0 have a separate payload digest which
can be used for the purpose and md5sum disabled (which would also deny
install of older packages).
Similarly (and more importantly) signatures can now be also required.
As a special case, the new payload digest added in 4.14.x is in the
main header which, if signed, makes the payload digest signature strength
too. Which would make it possible to drop V3 header+payload signatures
from package signing (which would make signing much faster) and still
have signature strength coverage for the entire package.
It's worth noting that when a verification level is active, --nodigest
and --nosignature seem to behave sort of counter-intuitively: these disablers
tell rpm not to try verification of those items, but the verification
level specifies what *must* be verified for a pass, so eg if signature
verify level is active, rpm -K --nosignatures will *always fail* because no
signatures could be verified.
This only implements the "policy" for the rpm -K style signature checking
path, installation is not covered yet as that's quite a different beast:
we don't want to enforce this at rpmReadPackage() level because of
API issues and assumptions (eg you couldn't read a package to discover
what key it was signed with, in order to import the key required to
successfully verify said package)
2018-04-27 18:27:02 +08:00
|
|
|
sinfo->wrapped = (vinfo->sigh == 0);
|
|
|
|
sinfo->strength = sinfo->type;
|
2017-04-28 15:32:24 +08:00
|
|
|
|
2018-04-24 16:05:35 +08:00
|
|
|
if (td == NULL) {
|
|
|
|
rc = RPMRC_NOTFOUND;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2017-05-11 15:40:28 +08:00
|
|
|
if (tinfo->tagtype && tinfo->tagtype != td->type) {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&sinfo->msg, _("%s tag %u: invalid type %u"),
|
2017-04-28 15:32:24 +08:00
|
|
|
origin, td->tag, td->type);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2017-05-11 15:40:28 +08:00
|
|
|
if (tinfo->tagcount && tinfo->tagcount != td->count) {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&sinfo->msg, _("%s: tag %u: invalid count %u"),
|
2017-04-28 15:32:24 +08:00
|
|
|
origin, td->tag, td->count);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (td->type) {
|
|
|
|
case RPM_STRING_TYPE:
|
|
|
|
case RPM_STRING_ARRAY_TYPE:
|
|
|
|
data = rpmtdGetString(td);
|
|
|
|
if (data)
|
|
|
|
dlen = strlen(data);
|
|
|
|
break;
|
|
|
|
case RPM_BIN_TYPE:
|
|
|
|
data = td->data;
|
|
|
|
dlen = td->count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MD5 has data length of 16, everything else is (much) larger */
|
|
|
|
if (sinfo->hashalgo && (data == NULL || dlen < 16)) {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&sinfo->msg, _("%s tag %u: invalid data %p (%u)"),
|
2017-04-28 15:32:24 +08:00
|
|
|
origin, td->tag, data, dlen);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (td->type == RPM_STRING_TYPE && td->size == 0)
|
|
|
|
td->size = dlen + 1;
|
|
|
|
|
2017-05-11 15:40:28 +08:00
|
|
|
if (tinfo->tagsize && (td->flags & RPMTD_IMMUTABLE) &&
|
|
|
|
tinfo->tagsize != td->size) {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&sinfo->msg, _("%s tag %u: invalid size %u"),
|
2017-04-28 15:32:24 +08:00
|
|
|
origin, td->tag, td->size);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sinfo->type == RPMSIG_SIGNATURE_TYPE) {
|
|
|
|
if (pgpPrtParams(data, dlen, PGPTAG_SIGNATURE, &sinfo->sig)) {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&sinfo->msg, _("%s tag %u: invalid OpenPGP signature"),
|
2017-04-28 15:32:24 +08:00
|
|
|
origin, td->tag);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
sinfo->hashalgo = pgpDigParamsAlgo(sinfo->sig, PGPVAL_HASHALGO);
|
|
|
|
sinfo->keyid = pgpGrab(sinfo->sig->signid+4, 4);
|
|
|
|
} else if (sinfo->type == RPMSIG_DIGEST_TYPE) {
|
2017-05-30 17:31:49 +08:00
|
|
|
if (td->type == RPM_BIN_TYPE) {
|
2017-04-28 15:32:24 +08:00
|
|
|
sinfo->dig = pgpHexStr(data, dlen);
|
2017-05-30 17:31:49 +08:00
|
|
|
} else {
|
|
|
|
if (!validHex(data, dlen)) {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&sinfo->msg,
|
|
|
|
_("%s: tag %u: invalid hex"), origin, td->tag);
|
2017-05-30 17:31:49 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
2017-04-28 15:32:24 +08:00
|
|
|
sinfo->dig = xstrdup(data);
|
2017-05-30 17:31:49 +08:00
|
|
|
}
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sinfo->hashalgo)
|
2017-05-15 16:14:18 +08:00
|
|
|
sinfo->id = (td->tag << 16) | rpmtdGetIndex(td);
|
2017-04-28 15:32:24 +08:00
|
|
|
|
|
|
|
rc = RPMRC_OK;
|
|
|
|
|
|
|
|
exit:
|
2018-04-05 19:46:36 +08:00
|
|
|
sinfo->rc = rc;
|
|
|
|
return;
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
|
2017-05-12 18:05:20 +08:00
|
|
|
static void rpmsinfoFini(struct rpmsinfo_s *sinfo)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
if (sinfo) {
|
|
|
|
if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
|
|
|
|
pgpDigParamsFree(sinfo->sig);
|
|
|
|
else if (sinfo->type == RPMSIG_DIGEST_TYPE)
|
|
|
|
free(sinfo->dig);
|
2018-04-10 16:24:19 +08:00
|
|
|
rpmDigestFinal(sinfo->ctx, NULL, NULL, 0);
|
2018-04-05 19:46:36 +08:00
|
|
|
free(sinfo->msg);
|
2017-05-24 16:20:35 +08:00
|
|
|
free(sinfo->descr);
|
2017-04-28 15:32:24 +08:00
|
|
|
memset(sinfo, 0, sizeof(*sinfo));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-12 18:05:20 +08:00
|
|
|
static int rpmsinfoDisabled(const struct rpmsinfo_s *sinfo, rpmVSFlags vsflags)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
if (!(sinfo->type & RPMSIG_VERIFIABLE_TYPE))
|
|
|
|
return 1;
|
|
|
|
if (vsflags & sinfo->disabler)
|
|
|
|
return 1;
|
|
|
|
if ((vsflags & RPMVSF_NEEDPAYLOAD) && (sinfo->range & RPMSIG_PAYLOAD))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-22 17:32:32 +08:00
|
|
|
static void rpmvsReserve(struct rpmvs_s *vs, int n)
|
|
|
|
{
|
|
|
|
if (vs->nsigs + n >= vs->nalloced) {
|
|
|
|
vs->nalloced = (vs->nsigs * 2) + n;
|
|
|
|
vs->sigs = xrealloc(vs->sigs, vs->nalloced * sizeof(*vs->sigs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-24 16:20:35 +08:00
|
|
|
const char *rpmsinfoDescr(struct rpmsinfo_s *sinfo)
|
|
|
|
{
|
|
|
|
if (sinfo->descr == NULL) {
|
|
|
|
switch (sinfo->type) {
|
|
|
|
case RPMSIG_DIGEST_TYPE:
|
2019-10-03 19:47:59 +08:00
|
|
|
rasprintf(&sinfo->descr, _("%s%s%s %s"),
|
2017-05-24 16:20:35 +08:00
|
|
|
rangeName(sinfo->range),
|
|
|
|
pgpValString(PGPVAL_HASHALGO, sinfo->hashalgo),
|
2019-10-03 19:47:59 +08:00
|
|
|
sinfo->alt ? " ALT" : "",
|
2017-05-24 16:20:35 +08:00
|
|
|
_("digest"));
|
|
|
|
break;
|
|
|
|
case RPMSIG_SIGNATURE_TYPE:
|
2018-04-13 20:08:09 +08:00
|
|
|
if (sinfo->sig) {
|
2018-06-06 17:44:11 +08:00
|
|
|
char *t = pgpIdentItem(sinfo->sig);
|
2018-04-13 20:08:09 +08:00
|
|
|
rasprintf(&sinfo->descr, _("%s%s"),
|
2018-06-06 17:44:11 +08:00
|
|
|
rangeName(sinfo->range), t);
|
|
|
|
free(t);
|
2018-04-13 20:08:09 +08:00
|
|
|
} else {
|
2019-10-03 19:47:59 +08:00
|
|
|
rasprintf(&sinfo->descr, _("%s%s%s %s"),
|
2018-04-13 20:08:09 +08:00
|
|
|
rangeName(sinfo->range),
|
|
|
|
pgpValString(PGPVAL_PUBKEYALGO, sinfo->sigalgo),
|
2019-10-03 19:47:59 +08:00
|
|
|
sinfo->alt ? " ALT" : "",
|
2018-04-13 20:08:09 +08:00
|
|
|
_("signature"));
|
|
|
|
}
|
2017-05-24 16:20:35 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sinfo->descr;
|
|
|
|
}
|
|
|
|
|
2018-04-05 19:46:36 +08:00
|
|
|
char *rpmsinfoMsg(struct rpmsinfo_s *sinfo)
|
2017-05-24 17:17:46 +08:00
|
|
|
{
|
|
|
|
char *msg = NULL;
|
2018-04-05 19:46:36 +08:00
|
|
|
if (sinfo->msg) {
|
2017-05-24 17:17:46 +08:00
|
|
|
rasprintf(&msg, "%s: %s (%s)",
|
2018-04-05 19:46:36 +08:00
|
|
|
rpmsinfoDescr(sinfo), rpmSigString(sinfo->rc), sinfo->msg);
|
2017-05-24 17:17:46 +08:00
|
|
|
} else {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&msg, "%s: %s",
|
|
|
|
rpmsinfoDescr(sinfo), rpmSigString(sinfo->rc));
|
2017-05-24 17:17:46 +08:00
|
|
|
}
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2018-04-05 18:58:44 +08:00
|
|
|
static void rpmvsAppend(struct rpmvs_s *sis, hdrblob blob,
|
|
|
|
const struct vfyinfo_s *vi, const struct vfytag_s *ti)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
2018-04-24 16:05:35 +08:00
|
|
|
if (!(vi->vi.type & RPMSIG_VERIFIABLE_TYPE))
|
2018-04-05 19:10:37 +08:00
|
|
|
return;
|
|
|
|
|
2018-04-24 16:05:35 +08:00
|
|
|
const char *o = (blob->il > blob->ril) ? _("header") : _("package");
|
2017-04-28 15:32:24 +08:00
|
|
|
struct rpmtd_s td;
|
2018-04-05 18:58:44 +08:00
|
|
|
rpmRC rc = hdrblobGet(blob, vi->tag, &td);
|
2018-04-24 16:05:35 +08:00
|
|
|
int nitems = (rc == RPMRC_OK) ? rpmtdCount(&td) : 1;
|
2017-05-22 17:32:32 +08:00
|
|
|
|
2018-04-24 16:05:35 +08:00
|
|
|
rpmvsReserve(sis, nitems);
|
2017-05-22 17:32:32 +08:00
|
|
|
|
2018-04-24 16:05:35 +08:00
|
|
|
if (!rpmsinfoDisabled(&vi->vi, sis->vsflags) && rc == RPMRC_OK) {
|
|
|
|
while (rpmtdNext(&td) >= 0) {
|
2018-04-05 19:46:36 +08:00
|
|
|
rpmsinfoInit(vi, ti, &td, o, &sis->sigs[sis->nsigs]);
|
2017-04-28 15:32:24 +08:00
|
|
|
sis->nsigs++;
|
|
|
|
}
|
2018-04-24 16:05:35 +08:00
|
|
|
} else {
|
|
|
|
rpmsinfoInit(vi, ti, NULL, o, &sis->sigs[sis->nsigs]);
|
|
|
|
sis->nsigs++;
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
2018-04-24 16:05:35 +08:00
|
|
|
rpmtdFreeData(&td);
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
|
2018-04-05 18:58:44 +08:00
|
|
|
void rpmvsAppendTag(struct rpmvs_s *vs, hdrblob blob, rpmTagVal tag)
|
|
|
|
{
|
|
|
|
int ix = sinfoLookup(tag);
|
|
|
|
if (ix >= 0) {
|
|
|
|
const struct vfyinfo_s *vi = &rpmvfyitems[ix];
|
|
|
|
const struct vfytag_s *ti = &rpmvfytags[ix];
|
|
|
|
rpmvsAppend(vs, blob, vi, ti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-27 16:22:41 +08:00
|
|
|
struct rpmvs_s *rpmvsCreate(int vfylevel, rpmVSFlags vsflags, rpmKeyring keyring)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
struct rpmvs_s *sis = xcalloc(1, sizeof(*sis));
|
2018-04-05 19:10:37 +08:00
|
|
|
sis->vsflags = vsflags;
|
2018-04-06 19:17:25 +08:00
|
|
|
sis->keyring = rpmKeyringLink(keyring);
|
2018-06-27 16:22:41 +08:00
|
|
|
sis->vfylevel = vfylevel;
|
2017-04-28 15:32:24 +08:00
|
|
|
|
2018-04-06 19:03:33 +08:00
|
|
|
return sis;
|
|
|
|
}
|
|
|
|
|
2018-04-06 19:28:18 +08:00
|
|
|
rpmVSFlags rpmvsFlags(struct rpmvs_s *vs)
|
|
|
|
{
|
|
|
|
return vs->vsflags;
|
|
|
|
}
|
|
|
|
|
2018-04-06 19:12:48 +08:00
|
|
|
void rpmvsInit(struct rpmvs_s *vs, hdrblob blob, rpmDigestBundle bundle)
|
2018-04-06 19:03:33 +08:00
|
|
|
{
|
|
|
|
const struct vfyinfo_s *si = &rpmvfyitems[0];
|
|
|
|
const struct vfytag_s *ti = &rpmvfytags[0];
|
|
|
|
|
2018-04-05 18:58:44 +08:00
|
|
|
for (; si->tag && ti->tag; si++, ti++) {
|
2018-04-13 18:35:25 +08:00
|
|
|
/* Ignore non-signature tags initially */
|
|
|
|
if (!si->sigh)
|
|
|
|
continue;
|
2018-04-06 19:03:33 +08:00
|
|
|
rpmvsAppend(vs, blob, si, ti);
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
2018-04-06 19:12:48 +08:00
|
|
|
vs->bundle = bundle;
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct rpmvs_s *rpmvsFree(struct rpmvs_s *sis)
|
|
|
|
{
|
|
|
|
if (sis) {
|
2018-04-06 19:17:25 +08:00
|
|
|
rpmKeyringFree(sis->keyring);
|
2017-04-28 15:32:24 +08:00
|
|
|
for (int i = 0; i < sis->nsigs; i++) {
|
|
|
|
rpmsinfoFini(&sis->sigs[i]);
|
|
|
|
}
|
|
|
|
free(sis->sigs);
|
|
|
|
free(sis);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-04-10 16:46:44 +08:00
|
|
|
void rpmvsInitRange(struct rpmvs_s *sis, int range)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
for (int i = 0; i < sis->nsigs; i++) {
|
|
|
|
struct rpmsinfo_s *sinfo = &sis->sigs[i];
|
|
|
|
if (sinfo->range & range) {
|
2018-04-05 19:46:36 +08:00
|
|
|
if (sinfo->rc == RPMRC_OK)
|
2018-04-06 19:12:48 +08:00
|
|
|
rpmDigestBundleAddID(sis->bundle, sinfo->hashalgo, sinfo->id, 0);
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 16:46:44 +08:00
|
|
|
void rpmvsFiniRange(struct rpmvs_s *sis, int range)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < sis->nsigs; i++) {
|
|
|
|
struct rpmsinfo_s *sinfo = &sis->sigs[i];
|
|
|
|
|
|
|
|
if (sinfo->range == range && sinfo->rc == RPMRC_OK) {
|
|
|
|
sinfo->ctx = rpmDigestBundleDupCtx(sis->bundle, sinfo->id);
|
2018-11-23 18:47:27 +08:00
|
|
|
/* Handle unsupported digests the same as disabled ones */
|
|
|
|
if (sinfo->ctx == NULL)
|
|
|
|
sinfo->rc = RPMRC_NOTFOUND;
|
2018-04-10 16:46:44 +08:00
|
|
|
rpmDigestBundleFinal(sis->bundle, sinfo->id, NULL, NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-11 19:21:47 +08:00
|
|
|
int rpmvsRange(struct rpmvs_s *vs)
|
|
|
|
{
|
|
|
|
int range = 0;
|
|
|
|
for (int i = 0; i < vs->nsigs; i++) {
|
|
|
|
if (rpmsinfoDisabled(&vs->sigs[i], vs->vsflags))
|
|
|
|
continue;
|
|
|
|
range |= vs->sigs[i].range;
|
|
|
|
}
|
|
|
|
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2018-05-09 16:12:03 +08:00
|
|
|
static int sinfoCmp(const void *a, const void *b)
|
2018-04-10 16:46:44 +08:00
|
|
|
{
|
|
|
|
const struct rpmsinfo_s *sa = a;
|
|
|
|
const struct rpmsinfo_s *sb = b;
|
2018-04-24 16:23:01 +08:00
|
|
|
int rc = sa->range - sb->range;
|
|
|
|
/* signatures before digests */
|
|
|
|
if (rc == 0)
|
|
|
|
rc = sb->type - sa->type;
|
2018-05-09 16:12:03 +08:00
|
|
|
/* strongest (in the "newer is better" sense) algos first */
|
|
|
|
if (rc == 0)
|
|
|
|
rc = sb->sigalgo - sb->sigalgo;
|
|
|
|
if (rc == 0)
|
|
|
|
rc = sb->hashalgo - sb->hashalgo;
|
|
|
|
/* last resort, these only makes sense from consistency POV */
|
|
|
|
if (rc == 0)
|
|
|
|
rc = sb->id - sa->id;
|
|
|
|
if (rc == 0)
|
|
|
|
rc = sb->disabler - sa->disabler;
|
2018-04-24 16:23:01 +08:00
|
|
|
return rc;
|
2018-04-10 16:46:44 +08:00
|
|
|
}
|
|
|
|
|
2019-10-03 19:47:59 +08:00
|
|
|
|
|
|
|
static const struct rpmsinfo_s *getAlt(const struct rpmvs_s *vs, const struct rpmsinfo_s *sinfo)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < vs->nsigs; i++) {
|
|
|
|
const struct rpmsinfo_s *alt = &vs->sigs[i];
|
|
|
|
if ((sinfo->id != alt->id) && (sinfo->disabler == alt->disabler))
|
|
|
|
return alt;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-06-19 15:15:37 +08:00
|
|
|
int rpmvsVerify(struct rpmvs_s *sis, int type,
|
2018-04-06 19:17:25 +08:00
|
|
|
rpmsinfoCb cb, void *cbdata)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
int failed = 0;
|
2018-03-08 19:22:49 +08:00
|
|
|
int cont = 1;
|
Implement configurable, mandatory signature/digest verify level for rpm -K
Traditionally rpm has verified whatever digests and signatures are present
(unless disabled) but there hasn't been any way to *require* either type
of verification, and making it all too easy to fool rpm into accepting
a tampered package whose signatures and digests have just been stripped
off and content modified. This commit adds support for required
verification level, possible levels being "none" (for traditional behavior
and default for now), "digest", "signature" and "all" (for both signatures
and digests).
What it means is that the specified level of validation is required for
the entire package file: eg on digest level, both the header and the
payload must have been validated with a digest. All digest algorithms are
considered equal for this purpose to abstract out version differences:
eg all valid rpm packages have *some* digest covering the entire package.
Traditionally the only digest covering the payload is the md5sum, but
packages built with rpm >= 4.14.0 have a separate payload digest which
can be used for the purpose and md5sum disabled (which would also deny
install of older packages).
Similarly (and more importantly) signatures can now be also required.
As a special case, the new payload digest added in 4.14.x is in the
main header which, if signed, makes the payload digest signature strength
too. Which would make it possible to drop V3 header+payload signatures
from package signing (which would make signing much faster) and still
have signature strength coverage for the entire package.
It's worth noting that when a verification level is active, --nodigest
and --nosignature seem to behave sort of counter-intuitively: these disablers
tell rpm not to try verification of those items, but the verification
level specifies what *must* be verified for a pass, so eg if signature
verify level is active, rpm -K --nosignatures will *always fail* because no
signatures could be verified.
This only implements the "policy" for the rpm -K style signature checking
path, installation is not covered yet as that's quite a different beast:
we don't want to enforce this at rpmReadPackage() level because of
API issues and assumptions (eg you couldn't read a package to discover
what key it was signed with, in order to import the key required to
successfully verify said package)
2018-04-27 18:27:02 +08:00
|
|
|
int range = 0;
|
|
|
|
int verified[3] = { 0, 0, 0 };
|
2017-04-28 15:32:24 +08:00
|
|
|
|
2018-05-09 16:12:03 +08:00
|
|
|
/* sort for consistency and rough "better comes first" semantics*/
|
|
|
|
qsort(sis->sigs, sis->nsigs, sizeof(*sis->sigs), sinfoCmp);
|
2018-04-10 16:46:44 +08:00
|
|
|
|
2018-03-08 19:22:49 +08:00
|
|
|
for (int i = 0; i < sis->nsigs && cont; i++) {
|
2017-04-28 15:32:24 +08:00
|
|
|
struct rpmsinfo_s *sinfo = &sis->sigs[i];
|
|
|
|
|
2018-04-10 16:46:44 +08:00
|
|
|
if (type & sinfo->type) {
|
Implement configurable, mandatory signature/digest verify level for rpm -K
Traditionally rpm has verified whatever digests and signatures are present
(unless disabled) but there hasn't been any way to *require* either type
of verification, and making it all too easy to fool rpm into accepting
a tampered package whose signatures and digests have just been stripped
off and content modified. This commit adds support for required
verification level, possible levels being "none" (for traditional behavior
and default for now), "digest", "signature" and "all" (for both signatures
and digests).
What it means is that the specified level of validation is required for
the entire package file: eg on digest level, both the header and the
payload must have been validated with a digest. All digest algorithms are
considered equal for this purpose to abstract out version differences:
eg all valid rpm packages have *some* digest covering the entire package.
Traditionally the only digest covering the payload is the md5sum, but
packages built with rpm >= 4.14.0 have a separate payload digest which
can be used for the purpose and md5sum disabled (which would also deny
install of older packages).
Similarly (and more importantly) signatures can now be also required.
As a special case, the new payload digest added in 4.14.x is in the
main header which, if signed, makes the payload digest signature strength
too. Which would make it possible to drop V3 header+payload signatures
from package signing (which would make signing much faster) and still
have signature strength coverage for the entire package.
It's worth noting that when a verification level is active, --nodigest
and --nosignature seem to behave sort of counter-intuitively: these disablers
tell rpm not to try verification of those items, but the verification
level specifies what *must* be verified for a pass, so eg if signature
verify level is active, rpm -K --nosignatures will *always fail* because no
signatures could be verified.
This only implements the "policy" for the rpm -K style signature checking
path, installation is not covered yet as that's quite a different beast:
we don't want to enforce this at rpmReadPackage() level because of
API issues and assumptions (eg you couldn't read a package to discover
what key it was signed with, in order to import the key required to
successfully verify said package)
2018-04-27 18:27:02 +08:00
|
|
|
/* Digests in signed header are signature strength */
|
|
|
|
if (sinfo->wrapped) {
|
|
|
|
if (verified[RPMSIG_SIGNATURE_TYPE] & RPMSIG_HEADER)
|
|
|
|
sinfo->strength = RPMSIG_SIGNATURE_TYPE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sinfo->ctx) {
|
2018-04-10 16:24:19 +08:00
|
|
|
rpmVerifySignature(sis->keyring, sinfo);
|
Implement configurable, mandatory signature/digest verify level for rpm -K
Traditionally rpm has verified whatever digests and signatures are present
(unless disabled) but there hasn't been any way to *require* either type
of verification, and making it all too easy to fool rpm into accepting
a tampered package whose signatures and digests have just been stripped
off and content modified. This commit adds support for required
verification level, possible levels being "none" (for traditional behavior
and default for now), "digest", "signature" and "all" (for both signatures
and digests).
What it means is that the specified level of validation is required for
the entire package file: eg on digest level, both the header and the
payload must have been validated with a digest. All digest algorithms are
considered equal for this purpose to abstract out version differences:
eg all valid rpm packages have *some* digest covering the entire package.
Traditionally the only digest covering the payload is the md5sum, but
packages built with rpm >= 4.14.0 have a separate payload digest which
can be used for the purpose and md5sum disabled (which would also deny
install of older packages).
Similarly (and more importantly) signatures can now be also required.
As a special case, the new payload digest added in 4.14.x is in the
main header which, if signed, makes the payload digest signature strength
too. Which would make it possible to drop V3 header+payload signatures
from package signing (which would make signing much faster) and still
have signature strength coverage for the entire package.
It's worth noting that when a verification level is active, --nodigest
and --nosignature seem to behave sort of counter-intuitively: these disablers
tell rpm not to try verification of those items, but the verification
level specifies what *must* be verified for a pass, so eg if signature
verify level is active, rpm -K --nosignatures will *always fail* because no
signatures could be verified.
This only implements the "policy" for the rpm -K style signature checking
path, installation is not covered yet as that's quite a different beast:
we don't want to enforce this at rpmReadPackage() level because of
API issues and assumptions (eg you couldn't read a package to discover
what key it was signed with, in order to import the key required to
successfully verify said package)
2018-04-27 18:27:02 +08:00
|
|
|
if (sinfo->rc == RPMRC_OK) {
|
|
|
|
verified[sinfo->type] |= sinfo->range;
|
|
|
|
verified[sinfo->strength] |= sinfo->range;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
range |= sinfo->range;
|
|
|
|
}
|
|
|
|
}
|
2017-04-28 15:32:24 +08:00
|
|
|
|
Implement configurable, mandatory signature/digest verify level for rpm -K
Traditionally rpm has verified whatever digests and signatures are present
(unless disabled) but there hasn't been any way to *require* either type
of verification, and making it all too easy to fool rpm into accepting
a tampered package whose signatures and digests have just been stripped
off and content modified. This commit adds support for required
verification level, possible levels being "none" (for traditional behavior
and default for now), "digest", "signature" and "all" (for both signatures
and digests).
What it means is that the specified level of validation is required for
the entire package file: eg on digest level, both the header and the
payload must have been validated with a digest. All digest algorithms are
considered equal for this purpose to abstract out version differences:
eg all valid rpm packages have *some* digest covering the entire package.
Traditionally the only digest covering the payload is the md5sum, but
packages built with rpm >= 4.14.0 have a separate payload digest which
can be used for the purpose and md5sum disabled (which would also deny
install of older packages).
Similarly (and more importantly) signatures can now be also required.
As a special case, the new payload digest added in 4.14.x is in the
main header which, if signed, makes the payload digest signature strength
too. Which would make it possible to drop V3 header+payload signatures
from package signing (which would make signing much faster) and still
have signature strength coverage for the entire package.
It's worth noting that when a verification level is active, --nodigest
and --nosignature seem to behave sort of counter-intuitively: these disablers
tell rpm not to try verification of those items, but the verification
level specifies what *must* be verified for a pass, so eg if signature
verify level is active, rpm -K --nosignatures will *always fail* because no
signatures could be verified.
This only implements the "policy" for the rpm -K style signature checking
path, installation is not covered yet as that's quite a different beast:
we don't want to enforce this at rpmReadPackage() level because of
API issues and assumptions (eg you couldn't read a package to discover
what key it was signed with, in order to import the key required to
successfully verify said package)
2018-04-27 18:27:02 +08:00
|
|
|
for (int i = 0; i < sis->nsigs && cont; i++) {
|
|
|
|
struct rpmsinfo_s *sinfo = &sis->sigs[i];
|
|
|
|
int strength = (sinfo->type | sinfo->strength);
|
|
|
|
int required = 0;
|
2017-04-28 15:32:24 +08:00
|
|
|
|
2019-10-03 19:47:59 +08:00
|
|
|
/* Ignore failure if an alternative exists and verifies ok */
|
|
|
|
if (sinfo->rc == RPMRC_FAIL) {
|
|
|
|
const struct rpmsinfo_s * alt = getAlt(sis, sinfo);
|
|
|
|
if (alt && alt->rc == RPMRC_OK)
|
|
|
|
sinfo->rc = RPMRC_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
2018-06-27 16:22:41 +08:00
|
|
|
if (sis->vfylevel & strength & RPMSIG_DIGEST_TYPE) {
|
Implement configurable, mandatory signature/digest verify level for rpm -K
Traditionally rpm has verified whatever digests and signatures are present
(unless disabled) but there hasn't been any way to *require* either type
of verification, and making it all too easy to fool rpm into accepting
a tampered package whose signatures and digests have just been stripped
off and content modified. This commit adds support for required
verification level, possible levels being "none" (for traditional behavior
and default for now), "digest", "signature" and "all" (for both signatures
and digests).
What it means is that the specified level of validation is required for
the entire package file: eg on digest level, both the header and the
payload must have been validated with a digest. All digest algorithms are
considered equal for this purpose to abstract out version differences:
eg all valid rpm packages have *some* digest covering the entire package.
Traditionally the only digest covering the payload is the md5sum, but
packages built with rpm >= 4.14.0 have a separate payload digest which
can be used for the purpose and md5sum disabled (which would also deny
install of older packages).
Similarly (and more importantly) signatures can now be also required.
As a special case, the new payload digest added in 4.14.x is in the
main header which, if signed, makes the payload digest signature strength
too. Which would make it possible to drop V3 header+payload signatures
from package signing (which would make signing much faster) and still
have signature strength coverage for the entire package.
It's worth noting that when a verification level is active, --nodigest
and --nosignature seem to behave sort of counter-intuitively: these disablers
tell rpm not to try verification of those items, but the verification
level specifies what *must* be verified for a pass, so eg if signature
verify level is active, rpm -K --nosignatures will *always fail* because no
signatures could be verified.
This only implements the "policy" for the rpm -K style signature checking
path, installation is not covered yet as that's quite a different beast:
we don't want to enforce this at rpmReadPackage() level because of
API issues and assumptions (eg you couldn't read a package to discover
what key it was signed with, in order to import the key required to
successfully verify said package)
2018-04-27 18:27:02 +08:00
|
|
|
int missing = (range & ~verified[RPMSIG_DIGEST_TYPE]);
|
|
|
|
required |= (missing & sinfo->range);
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
2018-06-27 16:22:41 +08:00
|
|
|
if (sis->vfylevel & strength & RPMSIG_SIGNATURE_TYPE) {
|
Implement configurable, mandatory signature/digest verify level for rpm -K
Traditionally rpm has verified whatever digests and signatures are present
(unless disabled) but there hasn't been any way to *require* either type
of verification, and making it all too easy to fool rpm into accepting
a tampered package whose signatures and digests have just been stripped
off and content modified. This commit adds support for required
verification level, possible levels being "none" (for traditional behavior
and default for now), "digest", "signature" and "all" (for both signatures
and digests).
What it means is that the specified level of validation is required for
the entire package file: eg on digest level, both the header and the
payload must have been validated with a digest. All digest algorithms are
considered equal for this purpose to abstract out version differences:
eg all valid rpm packages have *some* digest covering the entire package.
Traditionally the only digest covering the payload is the md5sum, but
packages built with rpm >= 4.14.0 have a separate payload digest which
can be used for the purpose and md5sum disabled (which would also deny
install of older packages).
Similarly (and more importantly) signatures can now be also required.
As a special case, the new payload digest added in 4.14.x is in the
main header which, if signed, makes the payload digest signature strength
too. Which would make it possible to drop V3 header+payload signatures
from package signing (which would make signing much faster) and still
have signature strength coverage for the entire package.
It's worth noting that when a verification level is active, --nodigest
and --nosignature seem to behave sort of counter-intuitively: these disablers
tell rpm not to try verification of those items, but the verification
level specifies what *must* be verified for a pass, so eg if signature
verify level is active, rpm -K --nosignatures will *always fail* because no
signatures could be verified.
This only implements the "policy" for the rpm -K style signature checking
path, installation is not covered yet as that's quite a different beast:
we don't want to enforce this at rpmReadPackage() level because of
API issues and assumptions (eg you couldn't read a package to discover
what key it was signed with, in order to import the key required to
successfully verify said package)
2018-04-27 18:27:02 +08:00
|
|
|
int missing = (range & ~verified[RPMSIG_SIGNATURE_TYPE]);
|
|
|
|
required |= (missing & sinfo->range);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!required && sinfo->rc == RPMRC_NOTFOUND)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (cb)
|
|
|
|
cont = cb(sinfo, cbdata);
|
|
|
|
|
|
|
|
if (sinfo->rc != RPMRC_OK)
|
|
|
|
failed = 1;
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char * rpmSigString(rpmRC res)
|
|
|
|
{
|
|
|
|
const char * str;
|
|
|
|
switch (res) {
|
|
|
|
case RPMRC_OK: str = "OK"; break;
|
|
|
|
case RPMRC_FAIL: str = "BAD"; break;
|
|
|
|
case RPMRC_NOKEY: str = "NOKEY"; break;
|
|
|
|
case RPMRC_NOTTRUSTED: str = "NOTTRUSTED"; break;
|
2018-04-24 16:05:35 +08:00
|
|
|
case RPMRC_NOTFOUND: str = "NOTFOUND"; break;
|
|
|
|
default: str = "UNKNOWN"; break;
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *rangeName(int range)
|
|
|
|
{
|
|
|
|
switch (range) {
|
|
|
|
case RPMSIG_HEADER: return _("Header ");
|
|
|
|
case RPMSIG_PAYLOAD: return _("Payload ");
|
|
|
|
}
|
|
|
|
/* trad. output for (RPMSIG_HEADER|RPMSIG_PAYLOAD) range is "" */
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2018-04-10 16:24:19 +08:00
|
|
|
static rpmRC verifyDigest(struct rpmsinfo_s *sinfo)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
rpmRC res = RPMRC_FAIL; /* assume failure */
|
|
|
|
char * dig = NULL;
|
|
|
|
size_t diglen = 0;
|
2018-04-10 16:24:19 +08:00
|
|
|
DIGEST_CTX ctx = rpmDigestDup(sinfo->ctx);
|
2017-04-28 15:32:24 +08:00
|
|
|
|
2017-05-24 16:23:48 +08:00
|
|
|
if (rpmDigestFinal(ctx, (void **)&dig, &diglen, 1) || diglen == 0)
|
2017-04-28 15:32:24 +08:00
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (strcasecmp(sinfo->dig, dig) == 0) {
|
|
|
|
res = RPMRC_OK;
|
|
|
|
} else {
|
2018-04-05 19:46:36 +08:00
|
|
|
rasprintf(&sinfo->msg, "Expected %s != %s", sinfo->dig, dig);
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
free(dig);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verify DSA/RSA signature.
|
|
|
|
* @param keyring pubkey keyring
|
|
|
|
* @param sinfo OpenPGP signature parameters
|
|
|
|
* @return RPMRC_OK on success
|
|
|
|
*/
|
|
|
|
static rpmRC
|
2018-04-10 16:24:19 +08:00
|
|
|
verifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
2018-04-10 16:24:19 +08:00
|
|
|
rpmRC res = rpmKeyringVerifySig(keyring, sinfo->sig, sinfo->ctx);
|
2017-04-28 15:32:24 +08:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-04-05 19:46:36 +08:00
|
|
|
static void
|
2018-04-10 16:24:19 +08:00
|
|
|
rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo)
|
2017-04-28 15:32:24 +08:00
|
|
|
{
|
|
|
|
if (sinfo->type == RPMSIG_DIGEST_TYPE)
|
2018-04-10 16:24:19 +08:00
|
|
|
sinfo->rc = verifyDigest(sinfo);
|
2017-04-28 15:32:24 +08:00
|
|
|
else if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
|
2018-04-10 16:24:19 +08:00
|
|
|
sinfo->rc = verifySignature(keyring, sinfo);
|
2018-04-05 19:46:36 +08:00
|
|
|
else
|
|
|
|
sinfo->rc = RPMRC_FAIL;
|
2017-04-28 15:32:24 +08:00
|
|
|
}
|