}
/* Eliminate broken digest values. */
- xx = headerDel(sigh, RPMSIGTAG_LEMD5_1);
- xx = headerDel(sigh, RPMSIGTAG_LEMD5_2);
xx = headerDel(sigh, RPMSIGTAG_BADSHA1_1);
xx = headerDel(sigh, RPMSIGTAG_BADSHA1_2);
/**
* @todo If the GPG key was known available, the md5 digest could be skipped.
*/
-static int readFile(FD_t fd, const char * fn, pgpDig dig)
+static int readFile(FD_t fd, const char * fn, pgpDig dig,
+ rpmDigestBundle plbundle, rpmDigestBundle hdrbundle)
{
unsigned char buf[4*BUFSIZ];
ssize_t count;
int rc = 1;
-
- dig->nbytes = 0;
+ Header h = NULL;
/* Read the header from the package. */
- { Header h = headerRead(fd, HEADER_MAGIC_YES);
- if (h == NULL) {
- rpmlog(RPMLOG_ERR, _("%s: headerRead failed\n"), fn);
- goto exit;
- }
-
- dig->nbytes += headerSizeof(h, HEADER_MAGIC_YES);
+ if ((h = headerRead(fd, HEADER_MAGIC_YES)) == NULL) {
+ rpmlog(RPMLOG_ERR, _("%s: headerRead failed\n"), fn);
+ goto exit;
+ }
- if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
- struct rpmtd_s utd;
-
- if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)){
- h = headerFree(h);
- rpmlog(RPMLOG_ERR,
- _("%s: Immutable header region could not be read. "
- "Corrupted package?\n"), fn);
- goto exit;
- }
- dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
- (void) rpmDigestUpdate(dig->hdrsha1ctx, rpm_header_magic, sizeof(rpm_header_magic));
- (void) rpmDigestUpdate(dig->hdrsha1ctx, utd.data, utd.count);
- dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
- (void) rpmDigestUpdate(dig->hdrmd5ctx, rpm_header_magic, sizeof(rpm_header_magic));
- (void) rpmDigestUpdate(dig->hdrmd5ctx, utd.data, utd.count);
- rpmtdFreeData(&utd);
+ if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
+ struct rpmtd_s utd;
+
+ if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)){
+ rpmlog(RPMLOG_ERR,
+ _("%s: Immutable header region could not be read. "
+ "Corrupted package?\n"), fn);
+ goto exit;
}
- h = headerFree(h);
+ rpmDigestBundleUpdate(hdrbundle, rpm_header_magic, sizeof(rpm_header_magic));
+ rpmDigestBundleUpdate(hdrbundle, utd.data, utd.count);
+ rpmtdFreeData(&utd);
}
/* Read the payload from the package. */
- while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
- dig->nbytes += count;
+ while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
if (count < 0) {
rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
goto exit;
}
- fdStealDigest(fd, dig);
rc = 0;
exit:
+ headerFree(h);
return rc;
}
+/* Parse the parameters from the OpenPGP packets that will be needed. */
+/* XXX TODO: unify with similar parsePGP() in package.c */
+static rpmRC parsePGP(rpmtd sigtd, const char *fn, pgpDig dig)
+{
+ rpmRC rc = RPMRC_FAIL;
+ int debug = (_print_pkts & rpmIsDebug());
+ if ((pgpPrtPkts(sigtd->data, sigtd->count, dig, debug) == 0) &&
+ (dig->signature.version == 3 || dig->signature.version == 4)) {
+ rc = RPMRC_OK;
+ } else {
+ rpmlog(RPMLOG_ERR,
+ _("skipping package %s with unverifiable V%u signature\n"), fn,
+ dig->signature.version);
+ }
+ return rc;
+}
+
+/*
+ * Figure best available signature.
+ * XXX TODO: Similar detection in rpmReadPackageFile(), unify these.
+ */
+static rpmSigTag bestSig(Header sigh, int nosignatures, int nodigests)
+{
+ rpmSigTag sigtag = 0;
+ if (sigtag == 0 && !nosignatures) {
+ if (headerIsEntry(sigh, RPMSIGTAG_DSA))
+ sigtag = RPMSIGTAG_DSA;
+ else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
+ sigtag = RPMSIGTAG_RSA;
+ else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
+ sigtag = RPMSIGTAG_GPG;
+ else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
+ sigtag = RPMSIGTAG_PGP;
+ }
+ if (sigtag == 0 && !nodigests) {
+ if (headerIsEntry(sigh, RPMSIGTAG_MD5))
+ sigtag = RPMSIGTAG_MD5;
+ else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
+ sigtag = RPMSIGTAG_SHA1; /* XXX never happens */
+ }
+ return sigtag;
+}
+
static const char *sigtagname(rpmSigTag sigtag, int upper)
{
const char *n = NULL;
case RPMSIGTAG_SHA1:
n = (upper ? "SHA1" : "sha1");
break;
- case RPMSIGTAG_LEMD5_2:
- case RPMSIGTAG_LEMD5_1:
case RPMSIGTAG_MD5:
n = (upper ? "MD5" : "md5");
break;
return n;
}
-int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd,
- const char * fn)
+/*
+ * Format sigcheck result for output, appending the message spew to buf and
+ * bad/missing keyids to keyprob.
+ *
+ * In verbose mode, just dump it all. Otherwise ok signatures
+ * are dumped lowercase, bad sigs uppercase and for PGP/GPG
+ * if misssing/untrusted key it's uppercase in parenthesis
+ * and stash the key id as <SIGTYPE>#<keyid>. Pfft.
+ */
+static void formatResult(rpmSigTag sigtag, rpmRC sigres, const char *result,
+ int havekey, char **keyprob, char **buf)
{
+ char *msg = NULL;
+ if (rpmIsVerbose()) {
+ rasprintf(&msg, " %s", result);
+ } else {
+ /* Check for missing / untrusted keys in result. */
+ const char *signame = sigtagname(sigtag, (sigres != RPMRC_OK));
+
+ if (havekey && (sigres == RPMRC_NOKEY || sigres == RPMRC_NOTTRUSTED)) {
+ const char *tempKey = strstr(result, "ey ID");
+ if (tempKey) {
+ char *keyid = strndup(tempKey + 6, 8);
+ char *idprob = NULL;
+ rasprintf(&idprob, " %s#%s", signame, keyid);
+ rstrcat(keyprob, idprob);
+ free(keyid);
+ free(idprob);
+ }
+ }
+ rasprintf(&msg, (*keyprob ? "(%s) " : "%s "), signame);
+ }
+ rstrcat(buf, msg);
+ free(msg);
+}
+
+static int rpmpkgVerifySigs(rpmKeyring keyring, rpmQueryFlags flags,
+ FD_t fd, const char *fn)
+{
+
char *buf = NULL;
- char * missingKeys, *untrustedKeys;
+ char *missingKeys = NULL;
+ char *untrustedKeys = NULL;
struct rpmtd_s sigtd;
rpmTag sigtag;
pgpDig dig = NULL;
pgpDigParams sigp;
Header sigh = NULL;
HeaderIterator hi = NULL;
- char * msg;
+ char * msg = NULL;
int res = 1; /* assume failure */
int xx;
- rpmRC rc, sigres;
- int failed;
- int nodigests = !(qva->qva_flags & VERIFY_DIGEST);
- int nosignatures = !(qva->qva_flags & VERIFY_SIGNATURE);
- rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
+ rpmRC rc;
+ int failed = 0;
+ int nodigests = !(flags & VERIFY_DIGEST);
+ int nosignatures = !(flags & VERIFY_SIGNATURE);
+ rpmDigestBundle plbundle = rpmDigestBundleNew();
+ rpmDigestBundle hdrbundle = rpmDigestBundleNew();
rpmlead lead = rpmLeadNew();
if ((rc = rpmLeadRead(fd, lead)) == RPMRC_OK) {
goto exit;
}
- msg = NULL;
rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
switch (rc) {
default:
msg = _free(msg);
/* Grab a hint of what needs doing to avoid duplication. */
- sigtag = 0;
- if (sigtag == 0 && !nosignatures) {
- if (headerIsEntry(sigh, RPMSIGTAG_DSA))
- sigtag = RPMSIGTAG_DSA;
- else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
- sigtag = RPMSIGTAG_RSA;
- else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
- sigtag = RPMSIGTAG_GPG;
- else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
- sigtag = RPMSIGTAG_PGP;
- }
- if (sigtag == 0 && !nodigests) {
- if (headerIsEntry(sigh, RPMSIGTAG_MD5))
- sigtag = RPMSIGTAG_MD5;
- else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
- sigtag = RPMSIGTAG_SHA1; /* XXX never happens */
- }
+ sigtag = bestSig(sigh, nosignatures, nodigests);
dig = pgpNewDig();
sigp = &dig->signature;
/* XXX RSA needs the hash_algo, so decode early. */
- if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP) {
+ if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP ||
+ sigtag == RPMSIGTAG_DSA || sigtag == RPMSIGTAG_GPG) {
xx = headerGet(sigh, sigtag, &sigtd, HEADERGET_DEFAULT);
xx = pgpPrtPkts(sigtd.data, sigtd.count, dig, 0);
rpmtdFreeData(&sigtd);
/* XXX assume same hash_algo in header-only and header+payload */
- if ((headerIsEntry(sigh, RPMSIGTAG_PGP)
- || headerIsEntry(sigh, RPMSIGTAG_PGP5))
- && dig->signature.hash_algo != PGPHASHALGO_MD5)
- fdInitDigest(fd, dig->signature.hash_algo, 0);
+ rpmDigestBundleAdd(plbundle, sigp->hash_algo, RPMDIGEST_NONE);
+ rpmDigestBundleAdd(hdrbundle, sigp->hash_algo, RPMDIGEST_NONE);
+ }
+
+ if (headerIsEntry(sigh, RPMSIGTAG_PGP) ||
+ headerIsEntry(sigh, RPMSIGTAG_PGP5) ||
+ headerIsEntry(sigh, RPMSIGTAG_MD5)) {
+ rpmDigestBundleAdd(plbundle, PGPHASHALGO_MD5, RPMDIGEST_NONE);
+ }
+ if (headerIsEntry(sigh, RPMSIGTAG_GPG)) {
+ rpmDigestBundleAdd(plbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
}
- if (headerIsEntry(sigh, RPMSIGTAG_PGP)
- || headerIsEntry(sigh, RPMSIGTAG_PGP5)
- || headerIsEntry(sigh, RPMSIGTAG_MD5))
- fdInitDigest(fd, PGPHASHALGO_MD5, 0);
- if (headerIsEntry(sigh, RPMSIGTAG_GPG))
- fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
+ /* always do sha1 hash of header */
+ rpmDigestBundleAdd(hdrbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
/* Read the file, generating digest(s) on the fly. */
- if (dig == NULL || sigp == NULL || readFile(fd, fn, dig)) {
+ fdSetBundle(fd, plbundle);
+ if (readFile(fd, fn, dig, plbundle, hdrbundle)) {
goto exit;
}
- failed = 0;
- missingKeys = NULL;
- untrustedKeys = NULL;
rasprintf(&buf, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
hi = headerInitIterator(sigh);
for (; headerNext(hi, &sigtd) != 0; rpmtdFreeData(&sigtd)) {
char *result = NULL;
int havekey = 0;
-
+ DIGEST_CTX ctx = NULL;
if (sigtd.data == NULL) /* XXX can't happen */
continue;
case RPMSIGTAG_DSA:
if (nosignatures)
continue;
- xx = pgpPrtPkts(sigtd.data, sigtd.count, dig,
- (_print_pkts & rpmIsDebug()));
-
- if (sigp->version != 3 && sigp->version != 4) {
- rpmlog(RPMLOG_ERR,
- _("skipping package %s with unverifiable V%u signature\n"),
- fn, sigp->version);
+ if (parsePGP(&sigtd, fn, dig) != RPMRC_OK) {
goto exit;
}
+ ctx = rpmDigestBundleDupCtx(havekey ? plbundle : hdrbundle,
+ dig->signature.hash_algo);
break;
case RPMSIGTAG_SHA1:
if (nodigests)
continue;
- /* XXX Don't bother with header sha1 if header dsa. */
- if (!nosignatures && sigtd.tag == RPMSIGTAG_DSA)
- continue;
+ ctx = rpmDigestBundleDupCtx(hdrbundle, PGPHASHALGO_SHA1);
break;
- case RPMSIGTAG_LEMD5_2:
- case RPMSIGTAG_LEMD5_1:
case RPMSIGTAG_MD5:
if (nodigests)
continue;
- /*
- * Don't bother with md5 if pgp, as RSA/MD5 is more reliable
- * than the -- now unsupported -- legacy md5 breakage.
- */
- if (!nosignatures && sigtd.tag == RPMSIGTAG_PGP)
- continue;
+ ctx = rpmDigestBundleDupCtx(plbundle, PGPHASHALGO_MD5);
break;
default:
continue;
break;
}
- sigres = rpmVerifySignature(keyring, &sigtd, dig, &result);
- if (sigres != RPMRC_OK) {
- failed = 1;
- }
+ rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &result);
+ rpmDigestFinal(ctx, NULL, NULL, 0);
- /*
- * In verbose mode, just dump it all. Otherwise ok signatures
- * are dumped lowercase, bad sigs uppercase and for PGP/GPG
- * if misssing/untrusted key it's uppercase in parenthesis
- * and stash the key id as <SIGTYPE>#<keyid>. Pfft.
- */
- msg = NULL;
- if (rpmIsVerbose()) {
- rasprintf(&msg, " %s", result);
- } else {
- const char *signame;
- char ** keyprob = NULL;
- signame = sigtagname(sigtd.tag, (sigres == RPMRC_OK ? 0 : 1));
-
- /*
- * Check for missing / untrusted keys in result. In theory
- * there could be several missing keys of which only
- * last is shown, in practise not.
- */
- if (havekey &&
- (sigres == RPMRC_NOKEY || sigres == RPMRC_NOTTRUSTED)) {
- const char *tempKey = NULL;
- char *keyid = NULL;
- keyprob = (sigres == RPMRC_NOKEY ?
- &missingKeys : &untrustedKeys);
- if (*keyprob) free(*keyprob);
- tempKey = strstr(result, "ey ID");
- if (tempKey)
- keyid = strndup(tempKey + 6, 8);
- rasprintf(keyprob, "%s#%s", signame, keyid);
- free(keyid);
- }
- rasprintf(&msg, (keyprob ? "(%s) " : "%s "), signame);
- }
+ formatResult(sigtd.tag, rc, result, havekey,
+ (rc == RPMRC_NOKEY ? &missingKeys : &untrustedKeys),
+ &buf);
free(result);
- rstrcat(&buf, msg);
- free(msg);
+ if (rc != RPMRC_OK) {
+ failed = 1;
+ }
+
}
res = failed;
exit:
free(buf);
+ rpmDigestBundleFree(hdrbundle);
+ rpmDigestBundleFree(plbundle);
+ fdSetBundle(fd, NULL); /* XXX avoid double-free from fd close */
sigh = rpmFreeSignature(sigh);
hi = headerFreeIterator(hi);
- rpmKeyringFree(keyring);
pgpFreeDig(dig);
return res;
}
+/* Wrapper around rpmkVerifySigs to preserve API */
+int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
+{
+ int rc = 1; /* assume failure */
+ if (ts && qva && fd && fn) {
+ rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
+ rc = rpmpkgVerifySigs(keyring, qva->qva_flags, fd, fn);
+ rpmKeyringFree(keyring);
+ }
+ return rc;
+}
+
int rpmcliSign(rpmts ts, QVA_t qva, ARGV_const_t argv)
{
const char * arg;
int res = 0;
int xx;
+ rpmKeyring keyring = NULL;
if (argv == NULL) return res;
break;
}
+ keyring = rpmtsGetKeyring(ts, 1);
while ((arg = *argv++) != NULL) {
FD_t fd;
rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
arg, Fstrerror(fd));
res++;
- } else if (rpmVerifySignatures(qva, ts, fd, arg)) {
+ } else if (rpmpkgVerifySigs(keyring, qva->qva_flags, fd, arg)) {
res++;
}
if (fd != NULL) xx = Fclose(fd);
+ rpmdbCheckSignals();
}
+ rpmKeyringFree(keyring);
return res;
}