Blame lib/rpmvs.c

2ff057
#include "system.h"
2ff057
2ff057
#include <pthread.h>
2ff057
#include <rpm/rpmkeyring.h>
2ff057
#include <rpm/rpmmacro.h>
2ff057
#include <rpm/rpmlog.h>
2ff057
#include "lib/rpmvs.h"
2ff057
#include "rpmio/digest.h"
2ff057
2ff057
#include "debug.h"
2ff057
2ff057
struct rpmvs_s {
2ff057
    struct rpmsinfo_s *sigs;
2ff057
    int nsigs;
2ff057
    int nalloced;
2ff057
    rpmVSFlags vsflags;
2ff057
    rpmDigestBundle bundle;
2ff057
    rpmKeyring keyring;
2ff057
    int vfylevel;
2ff057
};
2ff057
2ff057
struct vfytag_s {
2ff057
    rpmTagVal tag;
2ff057
    rpmTagType tagtype;
2ff057
    rpm_count_t tagcount;
2ff057
    rpm_count_t tagsize;
2ff057
};
2ff057
2ff057
static const struct vfytag_s rpmvfytags[] = {
2ff057
    {	RPMSIGTAG_SIZE,			RPM_BIN_TYPE,		0,	0, },
2ff057
    {	RPMSIGTAG_PGP,			RPM_BIN_TYPE,		0,	0, },
2ff057
    {	RPMSIGTAG_MD5,			RPM_BIN_TYPE,		0,	16, },
2ff057
    {	RPMSIGTAG_GPG,			RPM_BIN_TYPE,		0,	0, },
2ff057
    {	RPMSIGTAG_PAYLOADSIZE,		RPM_INT32_TYPE,		1,	4, },
2ff057
    {	RPMSIGTAG_RESERVEDSPACE,	RPM_BIN_TYPE,		0,	0, },
2ff057
    {	RPMTAG_DSAHEADER,		RPM_BIN_TYPE,		0,	0, },
2ff057
    {	RPMTAG_RSAHEADER,		RPM_BIN_TYPE,		0,	0, },
2ff057
    {	RPMTAG_SHA1HEADER,		RPM_STRING_TYPE,	1,	41, },
2ff057
    {	RPMSIGTAG_LONGSIZE,		RPM_INT64_TYPE,		1,	8, },
2ff057
    {	RPMSIGTAG_LONGARCHIVESIZE,	RPM_INT64_TYPE,		1,	8, },
2ff057
    {	RPMTAG_SHA256HEADER,		RPM_STRING_TYPE,	1,	65, },
2ff057
    {	RPMTAG_PAYLOADDIGEST,		RPM_STRING_ARRAY_TYPE,	0,	0, },
2ff057
    { 0 } /* sentinel */
2ff057
};
2ff057
2ff057
struct vfyinfo_s {
2ff057
    rpmTagVal tag;
2ff057
    int sigh;
2ff057
    struct rpmsinfo_s vi;
2ff057
};
2ff057
2ff057
static const struct vfyinfo_s rpmvfyitems[] = {
2ff057
    {	RPMSIGTAG_SIZE,			1,
2ff057
	{ RPMSIG_OTHER_TYPE,		0,
2ff057
	(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, 0, }, },
2ff057
    {	RPMSIGTAG_PGP,			1,
2ff057
	{ RPMSIG_SIGNATURE_TYPE,		RPMVSF_NORSA,
2ff057
	(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, PGPPUBKEYALGO_RSA, }, },
2ff057
    {	RPMSIGTAG_MD5,			1,
2ff057
	{ RPMSIG_DIGEST_TYPE,		RPMVSF_NOMD5,
2ff057
	(RPMSIG_HEADER|RPMSIG_PAYLOAD), PGPHASHALGO_MD5, }, },
2ff057
    {	RPMSIGTAG_GPG,			1,
2ff057
	{ RPMSIG_SIGNATURE_TYPE,		RPMVSF_NODSA,
2ff057
	(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, PGPPUBKEYALGO_DSA, }, },
2ff057
    {	RPMSIGTAG_PAYLOADSIZE,		1,
2ff057
	{ RPMSIG_OTHER_TYPE,		0,
2ff057
	(RPMSIG_PAYLOAD),		0, 0, }, },
2ff057
    {	RPMSIGTAG_RESERVEDSPACE,	1,
2ff057
	{ RPMSIG_OTHER_TYPE,		0,
2ff057
	0,				0, 0, }, },
2ff057
    {	RPMTAG_DSAHEADER,		1,
2ff057
	{ RPMSIG_SIGNATURE_TYPE,		RPMVSF_NODSAHEADER,
2ff057
	(RPMSIG_HEADER),		0, PGPPUBKEYALGO_DSA, }, },
2ff057
    {	RPMTAG_RSAHEADER,		1,
2ff057
	{ RPMSIG_SIGNATURE_TYPE,		RPMVSF_NORSAHEADER,
2ff057
	(RPMSIG_HEADER),		0, PGPPUBKEYALGO_RSA, }, },
2ff057
    {	RPMTAG_SHA1HEADER,		1,
2ff057
	{ RPMSIG_DIGEST_TYPE,		RPMVSF_NOSHA1HEADER,
2ff057
	(RPMSIG_HEADER),		PGPHASHALGO_SHA1, 0, }, },
2ff057
    {	RPMSIGTAG_LONGSIZE,		1,
2ff057
	{ RPMSIG_OTHER_TYPE, 		0,
2ff057
	(RPMSIG_HEADER|RPMSIG_PAYLOAD), 0, 0, }, },
2ff057
    {	RPMSIGTAG_LONGARCHIVESIZE,	1,
2ff057
	{ RPMSIG_OTHER_TYPE,		0,
2ff057
	(RPMSIG_HEADER|RPMSIG_PAYLOAD),	0, 0, }, },
2ff057
    {	RPMTAG_SHA256HEADER,		1,
2ff057
	{ RPMSIG_DIGEST_TYPE,		RPMVSF_NOSHA256HEADER,
2ff057
	(RPMSIG_HEADER),		PGPHASHALGO_SHA256, 0, }, },
2ff057
    {	RPMTAG_PAYLOADDIGEST,		0,
2ff057
	{ RPMSIG_DIGEST_TYPE,		RPMVSF_NOPAYLOAD,
2ff057
	(RPMSIG_PAYLOAD),		PGPHASHALGO_SHA256, 0, }, },
2ff057
    { 0 } /* sentinel */
2ff057
};
2ff057
2ff057
static const char *rangeName(int range);
2ff057
static const char * rpmSigString(rpmRC res);
2ff057
static void rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo);
2ff057
2ff057
static int sinfoLookup(rpmTagVal tag)
2ff057
{
2ff057
    const struct vfyinfo_s *start = &rpmvfyitems[0];
2ff057
    int ix = -1;
2ff057
    for (const struct vfyinfo_s *si = start; si->tag; si++) {
2ff057
	if (tag == si->tag) {
2ff057
	    ix = si - start;
2ff057
	    break;
2ff057
	}
2ff057
    }
2ff057
    return ix;
2ff057
}
2ff057
2ff057
static int validHex(const char *str, size_t slen)
2ff057
{
2ff057
    int valid = 0; /* Assume invalid */
2ff057
    const char *b;
2ff057
2ff057
    /* Our hex data is always even sized and at least sha-1 long */
2ff057
    if (slen % 2 || slen < 40)
2ff057
	goto exit;
2ff057
2ff057
    for (b = str ; *b != '\0'; b++) {
2ff057
	if (strchr("0123456789abcdefABCDEF", *b) == NULL)
2ff057
	    goto exit;
2ff057
    }
2ff057
    valid = 1;
2ff057
2ff057
exit:
2ff057
    return valid;
2ff057
}
2ff057
2ff057
static void rpmsinfoInit(const struct vfyinfo_s *vinfo,
2ff057
			  const struct vfytag_s *tinfo,
2ff057
			  rpmtd td,  const char *origin,
2ff057
			  struct rpmsinfo_s *sinfo)
2ff057
{
2ff057
    rpmRC rc = RPMRC_FAIL;
2ff057
    const void *data = NULL;
2ff057
    rpm_count_t dlen = 0;
2ff057
2ff057
    *sinfo = vinfo->vi; /* struct assignment */
2ff057
    sinfo->wrapped = (vinfo->sigh == 0);
2ff057
    sinfo->strength = sinfo->type;
2ff057
2ff057
    if (td == NULL) {
2ff057
	rc = RPMRC_NOTFOUND;
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    if (tinfo->tagtype && tinfo->tagtype != td->type) {
2ff057
	rasprintf(&sinfo->msg, _("%s tag %u: invalid type %u"),
2ff057
			origin, td->tag, td->type);
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    if (tinfo->tagcount && tinfo->tagcount != td->count) {
2ff057
	rasprintf(&sinfo->msg, _("%s: tag %u: invalid count %u"),
2ff057
			origin, td->tag, td->count);
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    switch (td->type) {
2ff057
    case RPM_STRING_TYPE:
2ff057
    case RPM_STRING_ARRAY_TYPE:
2ff057
	data = rpmtdGetString(td);
2ff057
	if (data)
2ff057
	    dlen = strlen(data);
2ff057
	break;
2ff057
    case RPM_BIN_TYPE:
2ff057
	data = td->data;
2ff057
	dlen = td->count;
2ff057
	break;
2ff057
    }
2ff057
2ff057
    /* MD5 has data length of 16, everything else is (much) larger */
2ff057
    if (sinfo->hashalgo && (data == NULL || dlen < 16)) {
2ff057
	rasprintf(&sinfo->msg, _("%s tag %u: invalid data %p (%u)"),
2ff057
			origin, td->tag, data, dlen);
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    if (td->type == RPM_STRING_TYPE && td->size == 0)
2ff057
	td->size = dlen + 1;
2ff057
2ff057
    if (tinfo->tagsize && (td->flags & RPMTD_IMMUTABLE) &&
2ff057
		tinfo->tagsize != td->size) {
2ff057
	rasprintf(&sinfo->msg, _("%s tag %u: invalid size %u"),
2ff057
			origin, td->tag, td->size);
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    if (sinfo->type == RPMSIG_SIGNATURE_TYPE) {
2ff057
	if (pgpPrtParams(data, dlen, PGPTAG_SIGNATURE, &sinfo->sig)) {
2ff057
	    rasprintf(&sinfo->msg, _("%s tag %u: invalid OpenPGP signature"),
2ff057
		    origin, td->tag);
2ff057
	    goto exit;
2ff057
	}
2ff057
	sinfo->hashalgo = pgpDigParamsAlgo(sinfo->sig, PGPVAL_HASHALGO);
2ff057
	sinfo->keyid = pgpGrab(sinfo->sig->signid+4, 4);
2ff057
    } else if (sinfo->type == RPMSIG_DIGEST_TYPE) {
2ff057
	if (td->type == RPM_BIN_TYPE) {
2ff057
	    sinfo->dig = pgpHexStr(data, dlen);
2ff057
	} else {
2ff057
	    if (!validHex(data, dlen)) {
2ff057
		rasprintf(&sinfo->msg,
2ff057
			_("%s: tag %u: invalid hex"), origin, td->tag);
2ff057
		goto exit;
2ff057
	    }
2ff057
	    sinfo->dig = xstrdup(data);
2ff057
	}
2ff057
    }
2ff057
2ff057
    if (sinfo->hashalgo)
2ff057
	sinfo->id = (td->tag << 16) | rpmtdGetIndex(td);
2ff057
2ff057
    rc = RPMRC_OK;
2ff057
2ff057
exit:
2ff057
    sinfo->rc = rc;
2ff057
    return;
2ff057
}
2ff057
2ff057
static void rpmsinfoFini(struct rpmsinfo_s *sinfo)
2ff057
{
2ff057
    if (sinfo) {
2ff057
	if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
2ff057
	    pgpDigParamsFree(sinfo->sig);
2ff057
	else if (sinfo->type == RPMSIG_DIGEST_TYPE)
2ff057
	    free(sinfo->dig);
2ff057
	rpmDigestFinal(sinfo->ctx, NULL, NULL, 0);
2ff057
	free(sinfo->msg);
2ff057
	free(sinfo->descr);
2ff057
	memset(sinfo, 0, sizeof(*sinfo));
2ff057
    }
2ff057
}
2ff057
2ff057
static int rpmsinfoDisabled(const struct rpmsinfo_s *sinfo, rpmVSFlags vsflags)
2ff057
{
2ff057
    if (!(sinfo->type & RPMSIG_VERIFIABLE_TYPE))
2ff057
	return 1;
2ff057
    if (vsflags & sinfo->disabler)
2ff057
	return 1;
2ff057
    if ((vsflags & RPMVSF_NEEDPAYLOAD) && (sinfo->range & RPMSIG_PAYLOAD))
2ff057
	return 1;
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static void rpmvsReserve(struct rpmvs_s *vs, int n)
2ff057
{
2ff057
    if (vs->nsigs + n >= vs->nalloced) {
2ff057
	vs->nalloced = (vs->nsigs * 2) + n;
2ff057
	vs->sigs = xrealloc(vs->sigs, vs->nalloced * sizeof(*vs->sigs));
2ff057
    }
2ff057
}
2ff057
2ff057
const char *rpmsinfoDescr(struct rpmsinfo_s *sinfo)
2ff057
{
2ff057
    if (sinfo->descr == NULL) {
2ff057
	switch (sinfo->type) {
2ff057
	case RPMSIG_DIGEST_TYPE:
2ff057
	    rasprintf(&sinfo->descr, _("%s%s %s"),
2ff057
		    rangeName(sinfo->range),
2ff057
		    pgpValString(PGPVAL_HASHALGO, sinfo->hashalgo),
2ff057
		    _("digest"));
2ff057
	    break;
2ff057
	case RPMSIG_SIGNATURE_TYPE:
2ff057
	    if (sinfo->sig) {
2ff057
		char *t = pgpIdentItem(sinfo->sig);
2ff057
		rasprintf(&sinfo->descr, _("%s%s"),
2ff057
			rangeName(sinfo->range), t);
2ff057
		free(t);
2ff057
	    } else {
2ff057
		rasprintf(&sinfo->descr, _("%s%s %s"),
2ff057
			rangeName(sinfo->range),
2ff057
			pgpValString(PGPVAL_PUBKEYALGO, sinfo->sigalgo),
2ff057
			_("signature"));
2ff057
	    }
2ff057
	    break;
2ff057
	}
2ff057
    }
2ff057
    return sinfo->descr;
2ff057
}
2ff057
2ff057
char *rpmsinfoMsg(struct rpmsinfo_s *sinfo)
2ff057
{
2ff057
    char *msg = NULL;
2ff057
    if (sinfo->msg) {
2ff057
	rasprintf(&msg, "%s: %s (%s)",
2ff057
		rpmsinfoDescr(sinfo), rpmSigString(sinfo->rc), sinfo->msg);
2ff057
    } else {
2ff057
	rasprintf(&msg, "%s: %s",
2ff057
		rpmsinfoDescr(sinfo), rpmSigString(sinfo->rc));
2ff057
    }
2ff057
    return msg;
2ff057
}
2ff057
2ff057
static void rpmvsAppend(struct rpmvs_s *sis, hdrblob blob,
2ff057
			const struct vfyinfo_s *vi, const struct vfytag_s *ti)
2ff057
{
2ff057
    if (!(vi->vi.type & RPMSIG_VERIFIABLE_TYPE))
2ff057
	return;
2ff057
2ff057
    const char *o = (blob->il > blob->ril) ? _("header") : _("package");
2ff057
    struct rpmtd_s td;
2ff057
    rpmRC rc = hdrblobGet(blob, vi->tag, &td);
2ff057
    int nitems = (rc == RPMRC_OK) ? rpmtdCount(&td) : 1;
2ff057
2ff057
    rpmvsReserve(sis, nitems);
2ff057
2ff057
    if (!rpmsinfoDisabled(&vi->vi, sis->vsflags) && rc == RPMRC_OK) {
2ff057
	while (rpmtdNext(&td) >= 0) {
2ff057
	    rpmsinfoInit(vi, ti, &td, o, &sis->sigs[sis->nsigs]);
2ff057
	    sis->nsigs++;
2ff057
	}
2ff057
    } else {
2ff057
	rpmsinfoInit(vi, ti, NULL, o, &sis->sigs[sis->nsigs]);
2ff057
	sis->nsigs++;
2ff057
    }
2ff057
    rpmtdFreeData(&td);
2ff057
}
2ff057
2ff057
void rpmvsAppendTag(struct rpmvs_s *vs, hdrblob blob, rpmTagVal tag)
2ff057
{
2ff057
    int ix = sinfoLookup(tag);
2ff057
    if (ix >= 0) {
2ff057
	const struct vfyinfo_s *vi = &rpmvfyitems[ix];
2ff057
	const struct vfytag_s *ti = &rpmvfytags[ix];
2ff057
	rpmvsAppend(vs, blob, vi, ti);
2ff057
    }
2ff057
}
2ff057
2ff057
struct rpmvs_s *rpmvsCreate(int vfylevel, rpmVSFlags vsflags, rpmKeyring keyring)
2ff057
{
2ff057
    struct rpmvs_s *sis = xcalloc(1, sizeof(*sis));
2ff057
    sis->vsflags = vsflags;
2ff057
    sis->keyring = rpmKeyringLink(keyring);
2ff057
    sis->vfylevel = vfylevel;
2ff057
2ff057
    return sis;
2ff057
}
2ff057
2ff057
rpmVSFlags rpmvsFlags(struct rpmvs_s *vs)
2ff057
{
2ff057
    return vs->vsflags;
2ff057
}
2ff057
2ff057
void rpmvsInit(struct rpmvs_s *vs, hdrblob blob, rpmDigestBundle bundle)
2ff057
{
2ff057
    const struct vfyinfo_s *si = &rpmvfyitems[0];
2ff057
    const struct vfytag_s *ti = &rpmvfytags[0];
2ff057
2ff057
    for (; si->tag && ti->tag; si++, ti++) {
2ff057
	/* Ignore non-signature tags initially */
2ff057
	if (!si->sigh)
2ff057
	    continue;
2ff057
	rpmvsAppend(vs, blob, si, ti);
2ff057
    }
2ff057
    vs->bundle = bundle;
2ff057
}
2ff057
2ff057
struct rpmvs_s *rpmvsFree(struct rpmvs_s *sis)
2ff057
{
2ff057
    if (sis) {
2ff057
	rpmKeyringFree(sis->keyring);
2ff057
	for (int i = 0; i < sis->nsigs; i++) {
2ff057
	    rpmsinfoFini(&sis->sigs[i]);
2ff057
	}
2ff057
	free(sis->sigs);
2ff057
	free(sis);
2ff057
    }
2ff057
    return NULL;
2ff057
}
2ff057
2ff057
void rpmvsInitRange(struct rpmvs_s *sis, int range)
2ff057
{
2ff057
    for (int i = 0; i < sis->nsigs; i++) {
2ff057
	struct rpmsinfo_s *sinfo = &sis->sigs[i];
2ff057
	if (sinfo->range & range) {
2ff057
	    if (sinfo->rc == RPMRC_OK)
2ff057
		rpmDigestBundleAddID(sis->bundle, sinfo->hashalgo, sinfo->id, 0);
2ff057
	}
2ff057
    }
2ff057
}
2ff057
2ff057
void rpmvsFiniRange(struct rpmvs_s *sis, int range)
2ff057
{
2ff057
    for (int i = 0; i < sis->nsigs; i++) {
2ff057
	struct rpmsinfo_s *sinfo = &sis->sigs[i];
2ff057
2ff057
	if (sinfo->range == range && sinfo->rc == RPMRC_OK) {
2ff057
	    sinfo->ctx = rpmDigestBundleDupCtx(sis->bundle, sinfo->id);
Panu Matilainen c1f390
	    /* Handle unsupported digests the same as disabled ones */
Panu Matilainen c1f390
	    if (sinfo->ctx == NULL)
Panu Matilainen c1f390
		sinfo->rc = RPMRC_NOTFOUND;
2ff057
	    rpmDigestBundleFinal(sis->bundle, sinfo->id, NULL, NULL, 0);
2ff057
	}
2ff057
    }
2ff057
}
2ff057
2ff057
static int sinfoCmp(const void *a, const void *b)
2ff057
{
2ff057
    const struct rpmsinfo_s *sa = a;
2ff057
    const struct rpmsinfo_s *sb = b;
2ff057
    int rc = sa->range - sb->range;
2ff057
    /* signatures before digests */
2ff057
    if (rc == 0)
2ff057
	rc = sb->type - sa->type;
2ff057
    /* strongest (in the "newer is better" sense) algos first */
2ff057
    if (rc == 0)
2ff057
	rc = sb->sigalgo - sb->sigalgo;
2ff057
    if (rc == 0)
2ff057
	rc = sb->hashalgo - sb->hashalgo;
2ff057
    /* last resort, these only makes sense from consistency POV */
2ff057
    if (rc == 0)
2ff057
	rc = sb->id - sa->id;
2ff057
    if (rc == 0)
2ff057
	rc = sb->disabler - sa->disabler;
2ff057
    return rc;
2ff057
}
2ff057
2ff057
int rpmvsVerify(struct rpmvs_s *sis, int type,
2ff057
		       rpmsinfoCb cb, void *cbdata)
2ff057
{
2ff057
    int failed = 0;
2ff057
    int cont = 1;
2ff057
    int range = 0;
2ff057
    int verified[3] = { 0, 0, 0 };
2ff057
2ff057
    /* sort for consistency and rough "better comes first" semantics*/
2ff057
    qsort(sis->sigs, sis->nsigs, sizeof(*sis->sigs), sinfoCmp);
2ff057
2ff057
    for (int i = 0; i < sis->nsigs && cont; i++) {
2ff057
	struct rpmsinfo_s *sinfo = &sis->sigs[i];
2ff057
2ff057
	if (type & sinfo->type) {
2ff057
	    /* Digests in signed header are signature strength */
2ff057
	    if (sinfo->wrapped) {
2ff057
		if (verified[RPMSIG_SIGNATURE_TYPE] & RPMSIG_HEADER)
2ff057
		    sinfo->strength = RPMSIG_SIGNATURE_TYPE;
2ff057
	    }
2ff057
2ff057
	    if (sinfo->ctx) {
2ff057
		rpmVerifySignature(sis->keyring, sinfo);
2ff057
		if (sinfo->rc == RPMRC_OK) {
2ff057
		    verified[sinfo->type] |= sinfo->range;
2ff057
		    verified[sinfo->strength] |= sinfo->range;
2ff057
		}
2ff057
	    }
2ff057
	    range |= sinfo->range;
2ff057
	}
2ff057
    }
2ff057
2ff057
    for (int i = 0; i < sis->nsigs && cont; i++) {
2ff057
	struct rpmsinfo_s *sinfo = &sis->sigs[i];
2ff057
	int strength = (sinfo->type | sinfo->strength);
2ff057
	int required = 0;
2ff057
2ff057
	if (sis->vfylevel & strength & RPMSIG_DIGEST_TYPE) {
2ff057
	    int missing = (range & ~verified[RPMSIG_DIGEST_TYPE]);
2ff057
	    required |= (missing & sinfo->range);
2ff057
	}
2ff057
	if (sis->vfylevel & strength & RPMSIG_SIGNATURE_TYPE) {
2ff057
	    int missing = (range & ~verified[RPMSIG_SIGNATURE_TYPE]);
2ff057
	    required |= (missing & sinfo->range);
2ff057
	}
2ff057
2ff057
	if (!required && sinfo->rc == RPMRC_NOTFOUND)
2ff057
	    continue;
2ff057
2ff057
	if (cb)
2ff057
	    cont = cb(sinfo, cbdata);
2ff057
2ff057
	if (sinfo->rc != RPMRC_OK)
2ff057
	    failed = 1;
2ff057
    }
2ff057
2ff057
    return failed;
2ff057
}
2ff057
2ff057
static const char * rpmSigString(rpmRC res)
2ff057
{
2ff057
    const char * str;
2ff057
    switch (res) {
2ff057
    case RPMRC_OK:		str = "OK";		break;
2ff057
    case RPMRC_FAIL:		str = "BAD";		break;
2ff057
    case RPMRC_NOKEY:		str = "NOKEY";		break;
2ff057
    case RPMRC_NOTTRUSTED:	str = "NOTTRUSTED";	break;
2ff057
    case RPMRC_NOTFOUND:	str = "NOTFOUND";	break;
2ff057
    default:			str = "UNKNOWN";	break;
2ff057
    }
2ff057
    return str;
2ff057
}
2ff057
2ff057
static const char *rangeName(int range)
2ff057
{
2ff057
    switch (range) {
2ff057
    case RPMSIG_HEADER:				return _("Header ");
2ff057
    case RPMSIG_PAYLOAD:			return _("Payload ");
2ff057
    }
2ff057
    /* trad. output for (RPMSIG_HEADER|RPMSIG_PAYLOAD) range is "" */
2ff057
    return "";
2ff057
}
2ff057
2ff057
static rpmRC verifyDigest(struct rpmsinfo_s *sinfo)
2ff057
{
2ff057
    rpmRC res = RPMRC_FAIL; /* assume failure */
2ff057
    char * dig = NULL;
2ff057
    size_t diglen = 0;
2ff057
    DIGEST_CTX ctx = rpmDigestDup(sinfo->ctx);
2ff057
2ff057
    if (rpmDigestFinal(ctx, (void **)&dig, &diglen, 1) || diglen == 0)
2ff057
	goto exit;
2ff057
2ff057
    if (strcasecmp(sinfo->dig, dig) == 0) {
2ff057
	res = RPMRC_OK;
2ff057
    } else {
2ff057
	rasprintf(&sinfo->msg, "Expected %s != %s", sinfo->dig, dig);
2ff057
    }
2ff057
2ff057
exit:
2ff057
    free(dig);
2ff057
    return res;
2ff057
}
2ff057
2ff057
/**
2ff057
 * Verify DSA/RSA signature.
2ff057
 * @param keyring	pubkey keyring
2ff057
 * @param sinfo		OpenPGP signature parameters
2ff057
 * @return 		RPMRC_OK on success
2ff057
 */
2ff057
static rpmRC
2ff057
verifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo)
2ff057
{
2ff057
    rpmRC res = rpmKeyringVerifySig(keyring, sinfo->sig, sinfo->ctx);
2ff057
2ff057
    return res;
2ff057
}
2ff057
2ff057
static void
2ff057
rpmVerifySignature(rpmKeyring keyring, struct rpmsinfo_s *sinfo)
2ff057
{
2ff057
    if (sinfo->type == RPMSIG_DIGEST_TYPE)
2ff057
	sinfo->rc = verifyDigest(sinfo);
2ff057
    else if (sinfo->type == RPMSIG_SIGNATURE_TYPE)
2ff057
	sinfo->rc = verifySignature(keyring, sinfo);
2ff057
    else
2ff057
	sinfo->rc = RPMRC_FAIL;
2ff057
}