static int sameSignature(rpmTagVal sigtag, Header h1, Header h2) { pgpDigParams sig1 = getSig(h1, sigtag); pgpDigParams sig2 = getSig(h2, sigtag);; int rc = pgpDigParamsCmp(sig1, sig2); pgpDigParamsFree(sig1); pgpDigParamsFree(sig2); return (rc == 0); }
static void rpmsinfoFini(struct rpmsinfo_s *sinfo) { if (sinfo) { if (sinfo->type == RPMSIG_SIGNATURE_TYPE) pgpDigParamsFree(sinfo->sig); else if (sinfo->type == RPMSIG_DIGEST_TYPE) free(sinfo->dig); free(sinfo->descr); memset(sinfo, 0, sizeof(*sinfo)); } }
static int haveSignature(rpmtd sigtd, Header h) { pgpDigParams sig1 = NULL; pgpDigParams sig2 = NULL; struct rpmtd_s oldtd; int rc = 0; /* assume no */ if (!headerGet(h, rpmtdTag(sigtd), &oldtd, HEADERGET_DEFAULT)) return rc; pgpPrtParams(sigtd->data, sigtd->count, PGPTAG_SIGNATURE, &sig1); while (rpmtdNext(&oldtd) >= 0 && rc == 0) { pgpPrtParams(oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2); if (pgpDigParamsCmp(sig1, sig2) == 0) rc = 1; pgpDigParamsFree(sig2); } pgpDigParamsFree(sig1); rpmtdFreeData(&oldtd); return rc; }
rpmPubkey rpmPubkeyFree(rpmPubkey key) { if (key == NULL) return NULL; if (key->nrefs > 1) return rpmPubkeyUnlink(key); pgpDigParamsFree(key->pgpkey); free(key->pkt); free(key); return NULL; }
/* * Validate generated signature and insert to header if it looks sane. * NSS doesn't support everything GPG does. Basic tests to see if the * generated signature is something we can use. * Return 0 on success, 1 on failure. */ static int putSignature(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen) { pgpDigParams sigp = NULL; rpmTagVal sigtag; struct rpmtd_s sigtd; int rc = 1; /* assume failure */ unsigned int hash_algo; unsigned int pubkey_algo; if (pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sigp)) { rpmlog(RPMLOG_ERR, _("Unsupported PGP signature\n")); goto exit; } hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO); if (rpmDigestLength(hash_algo) == 0) { rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %u\n"), hash_algo); goto exit; } pubkey_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO); switch (pubkey_algo) { case PGPPUBKEYALGO_DSA: sigtag = ishdr ? RPMSIGTAG_DSA : RPMSIGTAG_GPG; break; case PGPPUBKEYALGO_RSA: sigtag = ishdr ? RPMSIGTAG_RSA : RPMSIGTAG_PGP; break; default: rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %u\n"), pubkey_algo); goto exit; break; } /* Looks sane, insert into header */ rpmtdReset(&sigtd); sigtd.count = pktlen; sigtd.data = pkt; sigtd.type = RPM_BIN_TYPE; sigtd.tag = sigtag; /* Argh, reversed return codes */ rc = (headerPut(sigh, &sigtd, HEADERPUT_DEFAULT) == 0); exit: pgpDigParamsFree(sigp); return rc; }
/* * Validate generated signature and insert to header if it looks sane. * NSS doesn't support everything GPG does. Basic tests to see if the * generated signature is something we can use. * Return generated signature tag data on success, NULL on failure. */ static rpmtd makeSigTag(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen) { pgpDigParams sigp = NULL; rpmTagVal sigtag; rpmtd sigtd = NULL; unsigned int hash_algo; unsigned int pubkey_algo; if (pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sigp)) { rpmlog(RPMLOG_ERR, _("Unsupported PGP signature\n")); goto exit; } hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO); if (rpmDigestLength(hash_algo) == 0) { rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %u\n"), hash_algo); goto exit; } pubkey_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO); switch (pubkey_algo) { case PGPPUBKEYALGO_DSA: sigtag = ishdr ? RPMSIGTAG_DSA : RPMSIGTAG_GPG; break; case PGPPUBKEYALGO_RSA: sigtag = ishdr ? RPMSIGTAG_RSA : RPMSIGTAG_PGP; break; default: rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %u\n"), pubkey_algo); goto exit; break; } /* Looks sane, create the tag data */ sigtd = rpmtdNew(); sigtd->count = pktlen; sigtd->data = memcpy(xmalloc(pktlen), pkt, pktlen);; sigtd->type = RPM_BIN_TYPE; sigtd->tag = sigtag; sigtd->flags |= RPMTD_ALLOCED; exit: pgpDigParamsFree(sigp); return sigtd; }
/** * Display signature fingerprint and time. * @param td tag data container * @return formatted string */ static char * pgpsigFormat(rpmtd td) { char * val = NULL; if (rpmtdType(td) != RPM_BIN_TYPE) { val = xstrdup(_("(not a blob)")); } else { pgpDigParams sigp = NULL; if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) { val = xstrdup(_("(not an OpenPGP signature)")); } else { char dbuf[BUFSIZ]; char *keyid = pgpHexStr(sigp->signid, sizeof(sigp->signid)); unsigned int dateint = pgpGrab(sigp->time, sizeof(sigp->time)); time_t date = dateint; struct tm * tms = localtime(&date); unsigned int key_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO); unsigned int hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO); if (!(tms && strftime(dbuf, sizeof(dbuf), "%c", tms) > 0)) { snprintf(dbuf, sizeof(dbuf), _("Invalid date %u"), dateint); dbuf[sizeof(dbuf)-1] = '\0'; } rasprintf(&val, "%s/%s, %s, Key ID %s", pgpValString(PGPVAL_PUBKEYALGO, key_algo), pgpValString(PGPVAL_HASHALGO, hash_algo), dbuf, keyid); free(keyid); pgpDigParamsFree(sigp); } } return val; }
static int rpmpkgVerifySigs(rpmKeyring keyring, rpmQueryFlags flags, FD_t fd, const char *fn) { char *buf = NULL; char *missingKeys = NULL; char *untrustedKeys = NULL; struct rpmtd_s sigtd; pgpDigParams sig = NULL; Header sigh = NULL; HeaderIterator hi = NULL; char * msg = NULL; int res = 1; /* assume failure */ rpmRC rc; int failed = 0; int nodigests = !(flags & VERIFY_DIGEST); int nosignatures = !(flags & VERIFY_SIGNATURE); struct sigtInfo_s sinfo; rpmDigestBundle plbundle = rpmDigestBundleNew(); rpmDigestBundle hdrbundle = rpmDigestBundleNew(); if ((rc = rpmLeadRead(fd, NULL, NULL, &msg)) != RPMRC_OK) { goto exit; } rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg); if (rc != RPMRC_OK) { goto exit; } /* Initialize all digests we'll be needing */ hi = headerInitIterator(sigh); for (; headerNext(hi, &sigtd) != 0; rpmtdFreeData(&sigtd)) { rc = rpmSigInfoParse(&sigtd, "package", &sinfo, NULL, NULL); if (nosignatures && sinfo.type == RPMSIG_SIGNATURE_TYPE) continue; if (nodigests && sinfo.type == RPMSIG_DIGEST_TYPE) continue; if (rc == RPMRC_OK && sinfo.hashalgo) { rpmDigestBundleAdd(sinfo.payload ? plbundle : hdrbundle, sinfo.hashalgo, RPMDIGEST_NONE); } } hi = headerFreeIterator(hi); /* Read the file, generating digest(s) on the fly. */ fdSetBundle(fd, plbundle); if (readFile(fd, fn, plbundle, hdrbundle)) { goto exit; } rasprintf(&buf, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') ); hi = headerInitIterator(sigh); for (; headerNext(hi, &sigtd) != 0; rpmtdFreeData(&sigtd)) { char *result = NULL; DIGEST_CTX ctx = NULL; if (sigtd.data == NULL) /* XXX can't happen */ continue; /* Clean up parameters from previous sigtag. */ sig = pgpDigParamsFree(sig); /* Note: we permit failures to be ignored via disablers */ rc = rpmSigInfoParse(&sigtd, "package", &sinfo, &sig, &result); if (nosignatures && sinfo.type == RPMSIG_SIGNATURE_TYPE) continue; if (nodigests && sinfo.type == RPMSIG_DIGEST_TYPE) continue; if (sinfo.type == RPMSIG_OTHER_TYPE) continue; if (rc == RPMRC_OK) { ctx = rpmDigestBundleDupCtx(sinfo.payload ? plbundle : hdrbundle, sinfo.hashalgo); rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, &result); rpmDigestFinal(ctx, NULL, NULL, 0); } if (result) { formatResult(sigtd.tag, rc, result, (rc == RPMRC_NOKEY ? &missingKeys : &untrustedKeys), &buf); free(result); } if (rc != RPMRC_OK) { failed = 1; } } res = failed; if (rpmIsVerbose()) { rpmlog(RPMLOG_NOTICE, "%s", buf); } else { const char *ok = (failed ? _("NOT OK") : _("OK")); rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf, ok, missingKeys ? _(" (MISSING KEYS:") : "", missingKeys ? missingKeys : "", missingKeys ? _(") ") : "", untrustedKeys ? _(" (UNTRUSTED KEYS:") : "", untrustedKeys ? untrustedKeys : "", untrustedKeys ? _(")") : ""); } free(missingKeys); free(untrustedKeys); exit: if (res && msg != NULL) rpmlog(RPMLOG_ERR, "%s: %s\n", fn, msg); free(msg); free(buf); rpmDigestBundleFree(hdrbundle); rpmDigestBundleFree(plbundle); fdSetBundle(fd, NULL); /* XXX avoid double-free from fd close */ sigh = rpmFreeSignature(sigh); hi = headerFreeIterator(hi); pgpDigParamsFree(sig); return res; }
rpmRC rpmSigInfoParse(rpmtd td, const char *origin, struct sigtInfo_s *sinfo, pgpDigParams *sigp, char **msg) { rpmRC rc = RPMRC_FAIL; rpm_tagtype_t tagtype = 0; rpm_count_t tagsize = 0; pgpDigParams sig = NULL; int hexstring = 0; memset(sinfo, 0, sizeof(*sinfo)); switch (td->tag) { case RPMSIGTAG_GPG: case RPMSIGTAG_PGP5: /* XXX legacy */ case RPMSIGTAG_PGP: sinfo->payload = 1; /* fallthrough */ case RPMSIGTAG_RSA: case RPMSIGTAG_DSA: tagtype = RPM_BIN_TYPE; sinfo->type = RPMSIG_SIGNATURE_TYPE; break; case RPMSIGTAG_SHA1: tagsize = 41; /* includes trailing \0 */ tagtype = RPM_STRING_TYPE; hexstring = 1; sinfo->hashalgo = PGPHASHALGO_SHA1; sinfo->type = RPMSIG_DIGEST_TYPE; break; case RPMSIGTAG_MD5: tagtype = RPM_BIN_TYPE; tagsize = 16; sinfo->hashalgo = PGPHASHALGO_MD5; sinfo->type = RPMSIG_DIGEST_TYPE; sinfo->payload = 1; break; case RPMSIGTAG_SIZE: case RPMSIGTAG_PAYLOADSIZE: tagsize = 4; tagtype = RPM_INT32_TYPE; sinfo->type = RPMSIG_OTHER_TYPE; break; case RPMSIGTAG_LONGSIZE: case RPMSIGTAG_LONGARCHIVESIZE: tagsize = 8; tagtype = RPM_INT64_TYPE; sinfo->type = RPMSIG_OTHER_TYPE; break; case RPMSIGTAG_RESERVEDSPACE: tagtype = RPM_BIN_TYPE; sinfo->type = RPMSIG_OTHER_TYPE; break; default: /* anything unknown just falls through for now */ break; } if (tagtype && tagtype != td->type) { rasprintf(msg, _("%s tag %u: BAD, invalid type %u"), origin, td->tag, td->type); goto exit; } if (td->type == RPM_STRING_TYPE && td->size == 0) td->size = strlen(td->data) + 1; if (tagsize && (td->flags & RPMTD_IMMUTABLE) && tagsize != td->size) { rasprintf(msg, _("%s tag %u: BAD, invalid size %u"), origin, td->tag, td->size); goto exit; } if (hexstring) { for (const char * b = td->data; *b != '\0'; b++) { if (strchr("0123456789abcdefABCDEF", *b) == NULL) { rasprintf(msg, _("%s: tag %u: BAD, not hex"), origin, td->tag); goto exit; } } } if (sinfo->type == RPMSIG_SIGNATURE_TYPE) { if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sig)) { rasprintf(msg, _("%s tag %u: BAD, invalid OpenPGP signature"), origin, td->tag); goto exit; } sinfo->hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO); } rc = RPMRC_OK; if (sigp) *sigp = sig; else pgpDigParamsFree(sig); exit: return rc; }
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, FD_t fd, Header * hdrp, unsigned int *keyidp, char **msg) { pgpDigParams sig = NULL; Header sigh = NULL; rpmTagVal sigtag; struct rpmtd_s sigtd; struct sigtInfo_s sinfo; Header h = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int leadtype = -1; headerGetFlags hgeflags = HEADERGET_DEFAULT; if (hdrp) *hdrp = NULL; rpmtdReset(&sigtd); if ((rc = rpmLeadRead(fd, &leadtype, msg)) != RPMRC_OK) { /* Avoid message spew on manifests */ if (rc == RPMRC_NOTFOUND) { *msg = _free(*msg); } goto exit; } /* Read the signature header. */ rc = rpmReadSignature(fd, &sigh, msg); if (rc != RPMRC_OK) { goto exit; } #define _chk(_mask, _tag) \ (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag))) /* * Figger the most effective means of verification available, prefer * signatures over digests. Legacy header+payload entries are not used. * DSA will be preferred over RSA if both exist because tested first. */ sigtag = 0; if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) { sigtag = RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) { sigtag = RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) { sigtag = RPMSIGTAG_SHA1; } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; rc = rpmpkgReadHeader(fd, &h, msg); if (rc != RPMRC_OK || h == NULL) { goto exit; } /* Any digests or signatures to check? */ if (sigtag == 0) { rc = RPMRC_OK; goto exit; } /* Free up any previous "ok" message before signature/digest check */ *msg = _free(*msg); /* Retrieve the tag parameters from the signature header. */ if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) { rc = RPMRC_FAIL; goto exit; } if (rpmSigInfoParse(&sigtd, "package", &sinfo, &sig, msg) == RPMRC_OK) { struct rpmtd_s utd; DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE); if (headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) { rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, utd.data, utd.count); rpmtdFreeData(&utd); } /** @todo Implement disable/enable/warn/error/anal policy. */ rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, msg); rpmDigestFinal(ctx, NULL, NULL, 0); } else { rc = RPMRC_FAIL; } exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */ if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) { if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { uint32_t one = 1; headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1); } } /* * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's * what we use for differentiating binary vs source elsewhere. */ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) { headerPutString(h, RPMTAG_SOURCERPM, "(none)"); } /* * Convert legacy headers on the fly. Not having immutable region * equals a truly ancient package, do full retrofit. OTOH newer * packages might have been built with --nodirtokens, test and handle * the non-compressed filelist case separately. */ if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) headerConvert(h, HEADERCONV_RETROFIT_V3); else if (headerIsEntry(h, RPMTAG_OLDFILENAMES)) headerConvert(h, HEADERCONV_COMPRESSFILELIST); /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); if (keyidp) *keyidp = getKeyid(sig); } rpmtdFreeData(&sigtd); h = headerFree(h); pgpDigParamsFree(sig); sigh = headerFree(sigh); return rc; }
/* * Argument monster to verify header-only signature/digest if there is * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check. */ static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags, hdrblob blob, char **buf) { rpmRC rc = RPMRC_FAIL; pgpDigParams sig = NULL; struct rpmtd_s sigtd; struct entryInfo_s einfo; struct sigtInfo_s sinfo; rpmtdReset(&sigtd); memset(&einfo, 0, sizeof(einfo)); /* Find a header-only digest/signature tag. */ for (int i = blob->ril; i < blob->il; i++) { ei2h(blob->pe+i, &einfo); switch (einfo.tag) { case RPMTAG_SHA1HEADER: if (vsflags & RPMVSF_NOSHA1HEADER) break; if (sigtd.tag == 0) ei2td(&einfo, blob->dataStart, 0, &sigtd); break; case RPMTAG_RSAHEADER: if (vsflags & RPMVSF_NORSAHEADER) break; ei2td(&einfo, blob->dataStart, einfo.count, &sigtd); break; case RPMTAG_DSAHEADER: if (vsflags & RPMVSF_NODSAHEADER) break; ei2td(&einfo, blob->dataStart, einfo.count, &sigtd); break; default: break; } } /* No header-only digest/signature found, get outta here */ if (sigtd.tag == 0) { rc = RPMRC_NOTFOUND; goto exit; } if (rpmSigInfoParse(&sigtd, "header", &sinfo, &sig, buf)) goto exit; if (sinfo.hashalgo) { DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE); int32_t ildl[2] = { htonl(blob->ril), htonl(blob->rdl) }; rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, ildl, sizeof(ildl)); rpmDigestUpdate(ctx, blob->pe, (blob->ril * sizeof(*blob->pe))); rpmDigestUpdate(ctx, blob->dataStart, blob->rdl); rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf); rpmDigestFinal(ctx, NULL, NULL, 0); } exit: rpmtdFreeData(&sigtd); pgpDigParamsFree(sig); return rc; }
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, FD_t fd, const char * fn, Header * hdrp) { pgpDigParams sig = NULL; char buf[8*BUFSIZ]; ssize_t count; Header sigh = NULL; rpmTagVal sigtag; struct rpmtd_s sigtd; Header h = NULL; char * msg = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int leadtype = -1; headerGetFlags hgeflags = HEADERGET_DEFAULT; DIGEST_CTX ctx = NULL; if (hdrp) *hdrp = NULL; if (fn == NULL) fn = Fdescr(fd); rpmtdReset(&sigtd); if ((rc = rpmLeadRead(fd, NULL, &leadtype, &msg)) != RPMRC_OK) { /* Avoid message spew on manifests */ if (rc != RPMRC_NOTFOUND) rpmlog(RPMLOG_ERR, "%s: %s\n", fn, msg); free(msg); goto exit; } /* Read the signature header. */ rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn, (msg && *msg ? msg : "\n")); msg = _free(msg); goto exit; break; case RPMRC_OK: if (sigh == NULL) { rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn); rc = RPMRC_FAIL; goto exit; } break; } msg = _free(msg); #define _chk(_mask, _tag) \ (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag))) /* * Figger the most effective available signature. * Prefer signatures over digests, then header-only over header+payload. * DSA will be preferred over RSA if both exist because tested first. * Note that NEEDPAYLOAD prevents header+payload signatures and digests. */ sigtag = 0; if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) { sigtag = RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) { sigtag = RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_GPG)) { sigtag = RPMSIGTAG_GPG; fdInitDigest(fd, PGPHASHALGO_SHA1, 0); } else if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_PGP)) { sigtag = RPMSIGTAG_PGP; fdInitDigest(fd, PGPHASHALGO_MD5, 0); } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) { sigtag = RPMSIGTAG_SHA1; } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_MD5)) { sigtag = RPMSIGTAG_MD5; fdInitDigest(fd, PGPHASHALGO_MD5, 0); } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; msg = NULL; rc = rpmpkgReadHeader(keyring, vsflags, fd, &h, &msg); if (rc != RPMRC_OK || h == NULL) { rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s"), fn, (msg && *msg ? msg : "\n")); msg = _free(msg); goto exit; } msg = _free(msg); /* Any digests or signatures to check? */ if (sigtag == 0) { rc = RPMRC_OK; goto exit; } /* Retrieve the tag parameters from the signature header. */ if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) { rc = RPMRC_FAIL; goto exit; } switch (sigtag) { case RPMSIGTAG_RSA: case RPMSIGTAG_DSA: if (parsePGPSig(&sigtd, "package", fn, &sig)) goto exit; /* fallthrough */ case RPMSIGTAG_SHA1: { struct rpmtd_s utd; unsigned int hashalgo = (sigtag == RPMSIGTAG_SHA1) ? PGPHASHALGO_SHA1 : pgpDigParamsAlgo(sig, PGPVAL_HASHALGO); if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) break; ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE); (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); (void) rpmDigestUpdate(ctx, utd.data, utd.count); rpmtdFreeData(&utd); } break; case RPMSIGTAG_GPG: case RPMSIGTAG_PGP5: /* XXX legacy */ case RPMSIGTAG_PGP: if (parsePGPSig(&sigtd, "package", fn, &sig)) goto exit; /* fallthrough */ case RPMSIGTAG_MD5: /* Legacy signatures need the compressed payload in the digest too. */ 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)); rc = RPMRC_FAIL; goto exit; } ctx = rpmDigestBundleDupCtx(fdGetBundle(fd),(sigtag == RPMSIGTAG_MD5) ? PGPHASHALGO_MD5 : pgpDigParamsAlgo(sig, PGPVAL_HASHALGO)); break; default: break; } /** @todo Implement disable/enable/warn/error/anal policy. */ rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, &msg); switch (rc) { case RPMRC_OK: /* Signature is OK. */ rpmlog(RPMLOG_DEBUG, "%s: %s", fn, msg); break; case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ case RPMRC_NOKEY: /* Public key is unavailable. */ /* XXX Print NOKEY/NOTTRUSTED warning only once. */ { int lvl = (stashKeyid(sig) ? RPMLOG_DEBUG : RPMLOG_WARNING); rpmlog(lvl, "%s: %s", fn, msg); } break; case RPMRC_NOTFOUND: /* Signature is unknown type. */ rpmlog(RPMLOG_WARNING, "%s: %s", fn, msg); break; default: case RPMRC_FAIL: /* Signature does not verify. */ rpmlog(RPMLOG_ERR, "%s: %s", fn, msg); break; } free(msg); exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */ if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) { if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { uint32_t one = 1; headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1); } } /* * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's * what we use for differentiating binary vs source elsewhere. */ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) { headerPutString(h, RPMTAG_SOURCERPM, "(none)"); } /* * Convert legacy headers on the fly. Not having "new" style compressed * filenames is close enough estimate for legacy indication... */ if (!headerIsEntry(h, RPMTAG_DIRNAMES)) { headerConvert(h, HEADERCONV_RETROFIT_V3); } /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); } rpmtdFreeData(&sigtd); rpmDigestFinal(ctx, NULL, NULL, 0); h = headerFree(h); pgpDigParamsFree(sig); sigh = rpmFreeSignature(sigh); return rc; }
/* * Argument monster to verify header-only signature/digest if there is * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check. */ static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags, int il, int dl, int ril, int rdl, entryInfo pe, unsigned char * dataStart, char **buf) { size_t siglen = 0; rpmRC rc = RPMRC_FAIL; pgpDigParams sig = NULL; struct rpmtd_s sigtd; struct entryInfo_s info, einfo; unsigned int hashalgo = 0; rpmtdReset(&sigtd); memset(&info, 0, sizeof(info)); memset(&einfo, 0, sizeof(einfo)); /* Find a header-only digest/signature tag. */ for (int i = ril; i < il; i++) { if (headerVerifyInfo(1, dl, pe+i, &einfo, 0) != -1) { rasprintf(buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), i, einfo.tag, einfo.type, einfo.offset, einfo.count); goto exit; } switch (einfo.tag) { case RPMTAG_SHA1HEADER: { size_t blen = 0; unsigned const char * b; if (vsflags & RPMVSF_NOSHA1HEADER) break; for (b = dataStart + einfo.offset; *b != '\0'; b++) { if (strchr("0123456789abcdefABCDEF", *b) == NULL) break; blen++; } if (einfo.type != RPM_STRING_TYPE || *b != '\0' || blen != 40) { rasprintf(buf, _("hdr SHA1: BAD, not hex\n")); goto exit; } if (info.tag == 0) { info = einfo; /* structure assignment */ siglen = blen + 1; } } break; case RPMTAG_RSAHEADER: if (vsflags & RPMVSF_NORSAHEADER) break; if (einfo.type != RPM_BIN_TYPE) { rasprintf(buf, _("hdr RSA: BAD, not binary\n")); goto exit; } info = einfo; /* structure assignment */ siglen = info.count; break; case RPMTAG_DSAHEADER: if (vsflags & RPMVSF_NODSAHEADER) break; if (einfo.type != RPM_BIN_TYPE) { rasprintf(buf, _("hdr DSA: BAD, not binary\n")); goto exit; } info = einfo; /* structure assignment */ siglen = info.count; break; default: break; } } /* No header-only digest/signature found, get outta here */ if (info.tag == 0) { rc = RPMRC_NOTFOUND; goto exit; } sigtd.tag = info.tag; sigtd.type = info.type; sigtd.count = info.count; sigtd.data = memcpy(xmalloc(siglen), dataStart + info.offset, siglen); sigtd.flags = RPMTD_ALLOCED; switch (info.tag) { case RPMTAG_RSAHEADER: case RPMTAG_DSAHEADER: if (parsePGPSig(&sigtd, "header", NULL, &sig)) goto exit; hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO); break; case RPMTAG_SHA1HEADER: hashalgo = PGPHASHALGO_SHA1; break; default: break; } if (hashalgo) { DIGEST_CTX ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE); int32_t ildl[2] = { htonl(ril), htonl(rdl) }; rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, ildl, sizeof(ildl)); rpmDigestUpdate(ctx, pe, (ril * sizeof(*pe))); rpmDigestUpdate(ctx, dataStart, rdl); rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf); rpmDigestFinal(ctx, NULL, NULL, 0); } exit: rpmtdFreeData(&sigtd); pgpDigParamsFree(sig); return rc; }