Blame lib/rpmchecksig.c

2ff057
/** \ingroup rpmcli
2ff057
 * \file lib/rpmchecksig.c
2ff057
 * Verify the signature of a package.
2ff057
 */
2ff057
2ff057
#include "system.h"
2ff057
2ff057
#include <ctype.h>
2ff057
2ff057
#include <rpm/rpmlib.h>			/* RPMSIGTAG & related */
2ff057
#include <rpm/rpmpgp.h>
2ff057
#include <rpm/rpmcli.h>
2ff057
#include <rpm/rpmfileutil.h>	/* rpmMkTemp() */
2ff057
#include <rpm/rpmsq.h>
2ff057
#include <rpm/rpmts.h>
2ff057
#include <rpm/rpmlog.h>
2ff057
#include <rpm/rpmstring.h>
2ff057
#include <rpm/rpmkeyring.h>
2ff057
2ff057
#include "rpmio/rpmio_internal.h" 	/* fdSetBundle() */
2ff057
#include "lib/rpmlead.h"
2ff057
#include "lib/header_internal.h"
2ff057
#include "lib/rpmvs.h"
2ff057
2ff057
#include "debug.h"
2ff057
2ff057
int _print_pkts = 0;
2ff057
2ff057
static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen)
2ff057
{
2ff057
    char const * const pgpmark = "-----BEGIN PGP ";
2ff057
    size_t marklen = strlen(pgpmark);
2ff057
    int res = 0;
2ff057
    int keyno = 1;
2ff057
    char *start = strstr(buf, pgpmark);
2ff057
2ff057
    do {
2ff057
	uint8_t *pkt = NULL;
2ff057
	uint8_t *pkti = NULL;
2ff057
	size_t pktlen = 0;
2ff057
	size_t certlen;
2ff057
	
2ff057
	/* Read pgp packet. */
2ff057
	if (pgpParsePkts(start, &pkt, &pktlen) == PGPARMOR_PUBKEY) {
2ff057
	    pkti = pkt;
2ff057
2ff057
	    /* Iterate over certificates in pkt */
2ff057
	    while (pktlen > 0) {
2ff057
		if (pgpPubKeyCertLen(pkti, pktlen, &certlen)) {
2ff057
		    rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
2ff057
			    keyno);
2ff057
		    res++;
2ff057
		    break;
2ff057
		}
2ff057
2ff057
		/* Import pubkey certificate. */
2ff057
		if (rpmtsImportPubkey(ts, pkti, certlen) != RPMRC_OK) {
2ff057
		    rpmlog(RPMLOG_ERR, _("%s: key %d import failed.\n"), fn,
2ff057
			    keyno);
2ff057
		    res++;
2ff057
		}
2ff057
		pkti += certlen;
2ff057
		pktlen -= certlen;
2ff057
	    }
2ff057
	} else {
2ff057
	    rpmlog(RPMLOG_ERR, _("%s: key %d not an armored public key.\n"),
2ff057
		   fn, keyno);
2ff057
	    res++;
2ff057
	}
2ff057
	
2ff057
	/* See if there are more keys in the buffer */
2ff057
	if (start && start + marklen < buf + blen) {
2ff057
	    start = strstr(start + marklen, pgpmark);
2ff057
	} else {
2ff057
	    start = NULL;
2ff057
	}
2ff057
2ff057
	keyno++;
2ff057
	free(pkt);
2ff057
    } while (start != NULL);
2ff057
2ff057
    return res;
2ff057
}
2ff057
2ff057
int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv)
2ff057
{
2ff057
    int res = 0;
2ff057
    for (ARGV_const_t arg = argv; arg && *arg; arg++) {
2ff057
	const char *fn = *arg;
2ff057
	uint8_t *buf = NULL;
2ff057
	ssize_t blen = 0;
2ff057
	char *t = NULL;
2ff057
	int iorc;
2ff057
2ff057
	/* If arg looks like a keyid, then attempt keyserver retrieve. */
2ff057
	if (rstreqn(fn, "0x", 2)) {
2ff057
	    const char * s = fn + 2;
2ff057
	    int i;
2ff057
	    for (i = 0; *s && isxdigit(*s); s++, i++)
2ff057
		{};
2ff057
	    if (i == 8 || i == 16) {
2ff057
		t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
2ff057
		if (t && *t != '%')
2ff057
		    fn = t;
2ff057
	    }
2ff057
	}
2ff057
2ff057
	/* Read the file and try to import all contained keys */
2ff057
	iorc = rpmioSlurp(fn, &buf, &blen);
2ff057
	if (iorc || buf == NULL || blen < 64) {
2ff057
	    rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, iorc);
2ff057
	    res++;
2ff057
	} else {
2ff057
	    res += doImport(ts, fn, (char *)buf, blen);
2ff057
	}
2ff057
	
2ff057
	free(t);
2ff057
	free(buf);
2ff057
    }
2ff057
    return res;
2ff057
}
2ff057
2ff057
static int readFile(FD_t fd, char **msg)
2ff057
{
2ff057
    unsigned char buf[4*BUFSIZ];
2ff057
    ssize_t count;
2ff057
2ff057
    /* Read the payload from the package. */
2ff057
    while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
2ff057
    if (count < 0)
2ff057
	rasprintf(msg, _("Fread failed: %s"), Fstrerror(fd));
2ff057
2ff057
    return (count != 0);
2ff057
}
2ff057
2ff057
struct vfydata_s {
2ff057
    int seen;
2ff057
    int bad;
2ff057
    int verbose;
2ff057
};
2ff057
2ff057
static int vfyCb(struct rpmsinfo_s *sinfo, void *cbdata)
2ff057
{
2ff057
    struct vfydata_s *vd = cbdata;
2ff057
    vd->seen |= sinfo->type;
2ff057
    if (sinfo->rc != RPMRC_OK)
2ff057
	vd->bad |= sinfo->type;
2ff057
    if (vd->verbose) {
2ff057
	char *vsmsg = rpmsinfoMsg(sinfo);
2ff057
	rpmlog(RPMLOG_NOTICE, "    %s\n", vsmsg);
2ff057
	free(vsmsg);
2ff057
    }
2ff057
    return 1;
2ff057
}
2ff057
2ff057
rpmRC rpmpkgRead(struct rpmvs_s *vs, FD_t fd,
2ff057
		hdrblob *sigblobp, hdrblob *blobp, char **emsg)
2ff057
{
2ff057
2ff057
    char * msg = NULL;
2ff057
    rpmRC xx, rc = RPMRC_FAIL; /* assume failure */
2ff057
    hdrblob sigblob = hdrblobCreate();
2ff057
    hdrblob blob = hdrblobCreate();
2ff057
    rpmDigestBundle bundle = fdGetBundle(fd, 1); /* freed with fd */
2ff057
2ff057
    if ((xx = rpmLeadRead(fd, &msg)) != RPMRC_OK) {
2ff057
	/* Avoid message spew on manifests */
2ff057
	if (xx == RPMRC_NOTFOUND)
2ff057
	    msg = _free(msg);
2ff057
	rc = xx;
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    /* Read the signature header. Might not be in a contiguous region. */
2ff057
    if (hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg))
2ff057
	goto exit;
2ff057
2ff057
    rpmvsInit(vs, sigblob, bundle);
2ff057
2ff057
    /* Initialize digests ranging over the header */
2ff057
    rpmvsInitRange(vs, RPMSIG_HEADER);
2ff057
2ff057
    /* Read the header from the package. */
2ff057
    if (hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, blob, &msg))
2ff057
	goto exit;
2ff057
2ff057
    /* Finalize header range */
2ff057
    rpmvsFiniRange(vs, RPMSIG_HEADER);
2ff057
Packit Service bb4f4d
    /* Unless disabled, read the payload, generating digest(s) on the fly. */
Packit Service bb4f4d
    if (!(rpmvsFlags(vs) & RPMVSF_NEEDPAYLOAD)) {
Packit Service bb4f4d
	/* Fish interesting tags from the main header. This is a bit hacky... */
Packit Service bb4f4d
	rpmvsAppendTag(vs, blob, RPMTAG_PAYLOADDIGEST);
2ff057
2ff057
	/* Initialize digests ranging over the payload only */
2ff057
	rpmvsInitRange(vs, RPMSIG_PAYLOAD);
2ff057
2ff057
	if (readFile(fd, &msg))
2ff057
	    goto exit;
2ff057
2ff057
	/* Finalize payload range */
2ff057
	rpmvsFiniRange(vs, RPMSIG_PAYLOAD);
2ff057
	rpmvsFiniRange(vs, RPMSIG_HEADER|RPMSIG_PAYLOAD);
2ff057
    }
2ff057
2ff057
    if (sigblobp && blobp) {
2ff057
	*sigblobp = sigblob;
2ff057
	*blobp = blob;
2ff057
	sigblob = NULL;
2ff057
	blob = NULL;
2ff057
    }
2ff057
    rc = RPMRC_OK;
2ff057
2ff057
exit:
2ff057
    if (emsg)
2ff057
	*emsg = msg;
2ff057
    else
2ff057
	free(msg);
2ff057
    hdrblobFree(sigblob);
2ff057
    hdrblobFree(blob);
2ff057
    return rc;
2ff057
}
2ff057
2ff057
static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,
2ff057
			   FD_t fd, const char *fn)
2ff057
{
2ff057
    char *msg = NULL;
2ff057
    struct vfydata_s vd = { .seen = 0,
2ff057
			    .bad = 0,
2ff057
			    .verbose = rpmIsVerbose(),
2ff057
    };
2ff057
    int rc;
2ff057
    struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);
2ff057
2ff057
    rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : "");
2ff057
2ff057
    rc = rpmpkgRead(vs, fd, NULL, NULL, &msg;;
2ff057
2ff057
    if (rc)
2ff057
	goto exit;
2ff057
2ff057
    rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);
2ff057
2ff057
    if (!vd.verbose) {
2ff057
	if (vd.seen & RPMSIG_DIGEST_TYPE) {
2ff057
	    rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_DIGEST_TYPE) ?
2ff057
					_("DIGESTS") : _("digests"));
2ff057
	}
2ff057
	if (vd.seen & RPMSIG_SIGNATURE_TYPE) {
2ff057
	    rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ?
2ff057
					_("SIGNATURES") : _("signatures"));
2ff057
	}
2ff057
	rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));
2ff057
    }
2ff057
2ff057
exit:
2ff057
    if (rc && msg)
2ff057
	rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg);
2ff057
    rpmvsFree(vs);
2ff057
    free(msg);
2ff057
    return rc;
2ff057
}
2ff057
2ff057
/* Wrapper around rpmkVerifySigs to preserve API */
2ff057
int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
2ff057
{
2ff057
    int rc = 1; /* assume failure */
2ff057
    if (ts && qva && fd && fn) {
2ff057
	rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
2ff057
	int vfylevel = rpmtsVfyLevel(ts);
2ff057
	rc = rpmpkgVerifySigs(keyring, vfylevel, qva->qva_flags, fd, fn);
2ff057
    	rpmKeyringFree(keyring);
2ff057
    }
2ff057
    return rc;
2ff057
}
2ff057
2ff057
int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
2ff057
{
2ff057
    const char * arg;
2ff057
    int res = 0;
2ff057
    rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
2ff057
    rpmVSFlags vsflags = rpmtsVfyFlags(ts);
2ff057
    int vfylevel = rpmtsVfyLevel(ts);
2ff057
2ff057
    if (rpmcliQueryFlags & QUERY_DIGEST)
2ff057
	vsflags |= _RPMVSF_NODIGESTS;
2ff057
    if (rpmcliQueryFlags & QUERY_SIGNATURE)
2ff057
	vsflags |= _RPMVSF_NOSIGNATURES;
2ff057
    vsflags |= rpmcliVSFlags;
2ff057
    if (rpmcliVfyLevelMask) {
2ff057
	vfylevel &= ~rpmcliVfyLevelMask;
2ff057
	rpmtsSetVfyLevel(ts, vfylevel);
2ff057
    }
2ff057
2ff057
    while ((arg = *argv++) != NULL) {
2ff057
	FD_t fd = Fopen(arg, "r.ufdio");
2ff057
	if (fd == NULL || Ferror(fd)) {
2ff057
	    rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), 
2ff057
		     arg, Fstrerror(fd));
2ff057
	    res++;
2ff057
	} else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, arg)) {
2ff057
	    res++;
2ff057
	}
2ff057
2ff057
	Fclose(fd);
2ff057
	rpmsqPoll();
2ff057
    }
2ff057
    rpmKeyringFree(keyring);
2ff057
    return res;
2ff057
}