int showVerifyPackage(QVA_t qva, rpmts ts, Header h) { static int scareMem = 0; rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS); int spew = (qva->qva_mode != 'v'); /* XXX no output w verify(...) probe. */ int ec = 0; int i; rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem); uint32_t fc = rpmfiFC(fi); { /* Verify header digest/signature. */ if (qva->qva_flags & (VERIFY_DIGEST | VERIFY_SIGNATURE)) { const char * horigin = headerGetOrigin(h); const char * msg = NULL; size_t uhlen = 0; void * uh = headerUnload(h, &uhlen); int lvl = headerCheck(rpmtsDig(ts), uh, uhlen, &msg) == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG; rpmlog(lvl, "%s: %s\n", (horigin ? horigin : "verify"), (msg ? msg : "")); rpmtsCleanDig(ts); uh = _free(uh); msg = _free(msg); } /* Verify file digests. */ if (fc > 0 && (qva->qva_flags & VERIFY_FILES)) #if defined(_OPENMP) #pragma omp parallel for private(i) reduction(+:ec) #endif for (i = 0; i < (int)fc; i++) { int fflags = fi->fflags[i]; rpmvf vf; int rc; /* If not querying %config, skip config files. */ if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG)) continue; /* If not querying %doc, skip doc files. */ if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC)) continue; /* If not verifying %ghost, skip ghost files. */ /* XXX the broken!!! logic disables %ghost queries always. */ if (!(qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST)) continue; /* Gather per-file data into a carrier. */ vf = rpmvfNew(ts, fi, i, omitMask); /* Verify per-file metadata. */ rc = rpmvfVerify(vf, spew); if (rc) ec += rc; (void) rpmvfFree(vf); vf = NULL; } /* Run verify/sanity scripts (if any). */ if (qva->qva_flags & VERIFY_SCRIPT) { int rc; if (headerIsEntry(h, RPMTAG_VERIFYSCRIPT) || headerIsEntry(h, RPMTAG_SANITYCHECK)) { FD_t fdo = fdDup(STDOUT_FILENO); rc = rpmfiSetHeader(fi, h); if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0) ec += rc; if (fdo != NULL) rc = Fclose(fdo); rc = rpmfiSetHeader(fi, NULL); } } /* Verify dependency assertions. */ if (qva->qva_flags & VERIFY_DEPS) { int save_noise = _rpmds_unspecified_epoch_noise; int rc; /*@-mods@*/ if (rpmIsVerbose()) _rpmds_unspecified_epoch_noise = 1; if ((rc = verifyDependencies(qva, ts, h)) != 0) ec += rc; _rpmds_unspecified_epoch_noise = save_noise; /*@=mods@*/ } } fi = rpmfiFree(fi); return ec; }
/*@-mods@*/ rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp) { HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he)); HE_t she = (HE_t) memset(alloca(sizeof(*she)), 0, sizeof(*she)); pgpDig dig = rpmtsDig(ts); char buf[8*BUFSIZ]; ssize_t count; Header sigh = NULL; rpmtsOpX opx; rpmop op = NULL; size_t nb; unsigned ix; Header h = NULL; const char * msg = NULL; rpmVSFlags vsflags; rpmRC rc = RPMRC_FAIL; /* assume failure */ rpmop opsave = (rpmop) memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave)); int xx; pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); if (hdrp) *hdrp = NULL; assert(dig != NULL); (void) fdSetDig(fd, dig); /* Snapshot current I/O counters (cached persistent I/O reuses counters) */ (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ)); { const char item[] = "Lead"; msg = NULL; rc = rpmpkgRead(item, fd, NULL, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); /*@fallthrough@*/ case RPMRC_NOTFOUND: msg = _free(msg); goto exit; /*@notreached@*/ break; case RPMRC_OK: break; } msg = _free(msg); } { const char item[] = "Signature"; msg = NULL; rc = rpmpkgRead(item, fd, &sigh, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item, (msg && *msg ? msg : _("read failed\n"))); msg = _free(msg); goto exit; /*@notreached@*/ 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) (she->tag == 0 && !(vsflags & (_mask))) /* * 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. */ she->tag = (rpmTag)0; opx = (rpmtsOpX)0; vsflags = pgpDigVSFlags; if (_chk(RPMVSF_NOECDSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_ECDSA)) { she->tag = (rpmTag)RPMSIGTAG_ECDSA; } else if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) { she->tag = (rpmTag)RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) { she->tag = (rpmTag)RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) { she->tag = (rpmTag)RPMSIGTAG_SHA1; } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5)) { she->tag = (rpmTag)RPMSIGTAG_MD5; fdInitDigest(fd, PGPHASHALGO_MD5, 0); opx = RPMTS_OP_DIGEST; } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; msg = NULL; /* XXX stats will include header i/o and setup overhead. */ /* XXX repackaged packages have appended tags, legacy dig/sig check fails */ if (opx > 0) { op = (rpmop) pgpStatsAccumulator(dig, opx); (void) rpmswEnter(op, 0); } /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */ nb = fd->stats->ops[FDSTAT_READ].bytes; { const char item[] = "Header"; msg = NULL; rc = rpmpkgRead(item, fd, &h, &msg); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); msg = _free(msg); goto exit; } msg = _free(msg); } nb = fd->stats->ops[FDSTAT_READ].bytes - nb; /*@=type@*/ if (opx > 0 && op != NULL) { (void) rpmswExit(op, nb); op = NULL; } /* Any digests or signatures to check? */ if (she->tag == 0) { rc = RPMRC_OK; goto exit; } dig->nbytes = 0; /* Fish out the autosign pubkey (if present). */ he->tag = RPMTAG_PUBKEYS; xx = headerGet(h, he, 0); if (xx && he->p.argv != NULL && he->c > 0) switch (he->t) { default: break; case RPM_STRING_ARRAY_TYPE: ix = he->c - 1; /* XXX FIXME: assumes last pubkey */ dig->pub = _free(dig->pub); dig->publen = 0; { rpmiob iob = rpmiobNew(0); iob = rpmiobAppend(iob, he->p.argv[ix], 0); xx = pgpArmorUnwrap(iob, (rpmuint8_t **)&dig->pub, &dig->publen); iob = rpmiobFree(iob); } if (xx != PGPARMOR_PUBKEY) { dig->pub = _free(dig->pub); dig->publen = 0; } break; } he->p.ptr = _free(he->p.ptr); /* Retrieve the tag parameters from the signature header. */ xx = headerGet(sigh, she, 0); if (she->p.ptr == NULL) { rc = RPMRC_FAIL; goto exit; } /*@-ownedtrans -noeffect@*/ xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c); /*@=ownedtrans =noeffect@*/ switch ((rpmSigTag)she->tag) { default: /* XXX keep gcc quiet. */ assert(0); /*@notreached@*/ break; case RPMSIGTAG_RSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hrsa); break; case RPMSIGTAG_DSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hdsa); break; case RPMSIGTAG_ECDSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hecdsa); break; case RPMSIGTAG_SHA1: /* XXX dig->hsha? */ xx = hBlobDigest(h, dig, PGPHASHALGO_SHA1, &dig->hdsa); break; case RPMSIGTAG_MD5: /* Legacy signatures need the compressed payload in the digest too. */ op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ (void) rpmswEnter(op, 0); while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) dig->nbytes += count; (void) rpmswExit(op, dig->nbytes); op->count--; /* XXX one too many */ dig->nbytes += nb; /* XXX include size of header blob. */ if (count < 0) { rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd)); rc = RPMRC_FAIL; goto exit; } /* XXX Steal the digest-in-progress from the file handle. */ fdStealDigest(fd, dig); break; } /** @todo Implement disable/enable/warn/error/anal policy. */ buf[0] = '\0'; rc = rpmVerifySignature(dig, buf); switch (rc) { case RPMRC_OK: /* Signature is OK. */ rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf); break; case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ case RPMRC_NOKEY: /* Public key is unavailable. */ #ifndef DYING /* XXX Print NOKEY/NOTTRUSTED warning only once. */ { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING); rpmlog(lvl, "%s: %s\n", fn, buf); } break; case RPMRC_NOTFOUND: /* Signature is unknown type. */ rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf); break; #else case RPMRC_NOTFOUND: /* Signature is unknown type. */ case RPMRC_NOSIG: /* Signature is unavailable. */ #endif default: case RPMRC_FAIL: /* Signature does not verify. */ rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf); break; } exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); } (void)headerFree(h); h = NULL; /* Accumulate time reading package header. */ (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR), fdstat_op(fd, FDSTAT_READ)); (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR), opsave); #ifdef NOTYET /* Return RPMRC_NOSIG for MANDATORY signature verification. */ { rpmSigTag sigtag = pgpGetSigtag(dig); switch (sigtag) { default: rc = RPMRC_NOSIG; /*@fallthrough@*/ case RPMSIGTAG_RSA: case RPMSIGTAG_DSA: case RPMSIGTAG_ECDSA: break; } } #endif rpmtsCleanDig(ts); (void)headerFree(sigh); sigh = NULL; return rc; }