RPM Package Manager, CVS Repository http://rpm5.org/cvs/ ____________________________________________________________________________
Server: rpm5.org Name: Jeff Johnson Root: /v/rpm/cvs Email: j...@rpm5.org Module: rpm Date: 15-Apr-2016 20:42:14 Branch: rpm-5_4 Handle: 2016041518421400 Modified files: (Branch: rpm-5_4) rpm CHANGES rpm/lib rpmchecksig.c rpm/rpmdb pkgio.c Log: - pkgio: always verify hdr SHA1 if available. Summary: Revision Changes Path 1.3501.2.482+1 -0 rpm/CHANGES 1.240.2.19 +11 -13 rpm/lib/rpmchecksig.c 1.121.2.22 +422 -147 rpm/rpmdb/pkgio.c ____________________________________________________________________________ patch -p0 <<'@@ .' Index: rpm/CHANGES ============================================================================ $ cvs diff -u -r1.3501.2.481 -r1.3501.2.482 CHANGES --- rpm/CHANGES 15 Apr 2016 18:23:56 -0000 1.3501.2.481 +++ rpm/CHANGES 15 Apr 2016 18:42:14 -0000 1.3501.2.482 @@ -1,4 +1,5 @@ 5.4.15 -> 5.4.16: + - jbj: pkgio: always verify hdr SHA1 if available. - jbj: header: fix: tighter checks on index entries and data. - jbj: rpmpgp: fix: handle packet underruns. - jbj: rpmlog: colorized spewage. @@ . patch -p0 <<'@@ .' Index: rpm/lib/rpmchecksig.c ============================================================================ $ cvs diff -u -r1.240.2.18 -r1.240.2.19 rpmchecksig.c --- rpm/lib/rpmchecksig.c 4 Apr 2016 18:42:29 -0000 1.240.2.18 +++ rpm/lib/rpmchecksig.c 15 Apr 2016 18:42:14 -0000 1.240.2.19 @@ -1068,8 +1068,8 @@ char buf[8192], * b; char missingKeys[7164], * m; char untrustedKeys[7164], * u; - pgpDig dig; - pgpDigParams sigp; + pgpDig dig = rpmtsDig(ts); + pgpDigParams sigp = pgpGetSignature(dig); Header sigh = NULL; HeaderIterator hi = NULL; int res = 0; @@ -1080,6 +1080,10 @@ int nosignatures = !(qva->qva_flags & VERIFY_SIGNATURE); pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); +/*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */ + (void) fdSetDig(fd, dig); +/*@=mods@*/ + { { const char item[] = "Lead"; const char * msg = NULL; @@ -1137,12 +1141,6 @@ she->tag = (rpmTag) RPMSIGTAG_SHA1; /* XXX never happens */ } - dig = rpmtsDig(ts); -/*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */ - (void) fdSetDig(fd, dig); -/*@=mods@*/ - sigp = pgpGetSignature(dig); - /* XXX DSA2/RSA/ECDSA needs the hash_algo, so decode early. */ switch ((rpmSigTag) she->tag) { default: @@ -1195,10 +1193,6 @@ /* Clean up parameters from previous she->tag. */ pgpDigClean(dig); -/*@-ownedtrans -noeffect@*/ - xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c); -/*@=ownedtrans =noeffect@*/ - switch ((rpmSigTag)she->tag) { /* XXX assumes RPMSIGTAG_{DSA,RSA,ECDSA} are mutually exclusive */ case RPMSIGTAG_RSA: @@ -1215,7 +1209,7 @@ _("skipping package %s with unverifiable V%u signature\n"), fn, sigp->version); res++; - goto exit; + continue; } /*@switchbreak@*/ break; case RPMSIGTAG_SHA1: @@ -1234,6 +1228,10 @@ /*@notreached@*/ /*@switchbreak@*/ break; } +/*@-ownedtrans -noeffect@*/ + xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c); +/*@=ownedtrans =noeffect@*/ + sigres = rpmVerifySignature(dig, result); if (sigres) { @@ . patch -p0 <<'@@ .' Index: rpm/rpmdb/pkgio.c ============================================================================ $ cvs diff -u -r1.121.2.21 -r1.121.2.22 pkgio.c --- rpm/rpmdb/pkgio.c 11 Apr 2016 09:13:28 -0000 1.121.2.21 +++ rpm/rpmdb/pkgio.c 15 Apr 2016 18:42:14 -0000 1.121.2.22 @@ -502,6 +502,7 @@ static rpmRC rdLead(FD_t fd, /*@out@*/ /*@null@*/ void * ptr, /*@null@*/ const char ** msg) { +static const char origin[] = "lead "; /* XXX +trailing space */ struct rpmlead ** leadp = (struct rpmlead **) ptr; struct rpmlead * l = (struct rpmlead *) xcalloc(1, sizeof(*l)); char buf[BUFSIZ]; @@ -520,13 +521,13 @@ if ((xx = (int) timedRead(fd, (char *)l, sizeof(*l))) != (int) sizeof(*l)) { if (Ferror(fd)) { (void) snprintf(buf, sizeof(buf), - _("lead size(%u): BAD, read(%d), %s(%d)"), - (unsigned)sizeof(*l), xx, Fstrerror(fd), errno); + _("%ssize(%u): BAD, read(%d), %s(%d)"), + origin, (unsigned)sizeof(*l), xx, Fstrerror(fd), errno); rc = rc_fail; } else { (void) snprintf(buf, sizeof(buf), - _("lead size(%u): BAD, read(%d), %s(%d)"), - (unsigned)sizeof(*l), xx, strerror(errno), errno); + _("%ssize(%u): BAD, read(%d), %s(%d)"), + origin, (unsigned)sizeof(*l), xx, strerror(errno), errno); rc = rc_notfound; /* XXX silently ignore a short read */ } goto exit; @@ -563,8 +564,8 @@ (void) rpmxarSwapBuf(xar, NULL, 0, &b, &nb); if (nb != sizeof(*l)) { (void) snprintf(buf, sizeof(buf), - _("lead size(%u): BAD, xar read(%u)"), - (unsigned)sizeof(*l), (unsigned)nb); + _("%ssize(%u): BAD, xar read(%u)"), + origin, (unsigned)sizeof(*l), (unsigned)nb); b = _free(b); rc = rc_fail; goto exit; @@ -588,7 +589,7 @@ switch (l->major) { default: (void) snprintf(buf, sizeof(buf), - _("lead version(%u): UNSUPPORTED"), (unsigned) l->major); + _("%sversion(%u): UNSUPPORTED"), origin, (unsigned) l->major); rc = rc_notfound; /* XXX silently ignore invalid major */ goto exit; /*@notreached@*/ break; @@ -599,7 +600,7 @@ if (l->signature_type != 5) { /* RPMSIGTYPE_HEADERSIG */ (void) snprintf(buf, sizeof(buf), - _("sigh type(%u): UNSUPPORTED"), (unsigned) l->signature_type); + _("%stype(%u): UNSUPPORTED"), "sigh ", (unsigned) l->signature_type); rc = rc_notfound; /* XXX silently ignore signature type */ goto exit; } @@ -721,6 +722,23 @@ return buf; } +static rpmRC chkPgpPktLen(const char * origin, rpmuint32_t tag, + const void *sig, rpmuint32_t siglen, pgpPkt pp, + char *b, size_t nb) +{ + int xx = pgpPktLen(sig, siglen, pp); + rpmRC rc = RPMRC_OK; + + if (xx < 0 || xx != (int)siglen) { + (void) snprintf(b, nb, + _("%stag(%u): BAD, OpenPGP count(%u) != pktlen(%d)"), + origin, tag, siglen, xx); + rc = RPMRC_FAIL; + } + + return rc; +} + /** * Read (and verify header+payload size) signature header. * @param fd file handle @@ -731,6 +749,7 @@ static rpmRC rdSignature(FD_t fd, /*@out@*/ /*@null@*/ void * ptr, /*@null@*/ const char ** msg) { +static const char origin[] = "sigh "; /* XXX +trailing space */ HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he)); Header * sighp = (Header *) ptr; char buf[BUFSIZ]; @@ -739,6 +758,7 @@ rpmuint32_t dl; rpmuint32_t * ei = NULL; entryInfo pe; + size_t pvlen; size_t startoff; size_t nb; rpmuint32_t ril = 0; @@ -753,9 +773,15 @@ int xx; struct stat sb, *st = &sb; static int map = 1; +pgpDig dig = pgpDigLink(fdGetDig(fd)); +rpmuint32_t sigtag = 0; +rpmuint32_t sigtype = 0; +const void * sig = NULL; +rpmuint32_t siglen = 0; +pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); if (_pkgio_debug) -fprintf(stderr, "--> rdSignature(%p, %p, %p)\n", fd, ptr, msg); +fprintf(stderr, "--> rdSignature(%p, %p, %p) dig %p\n", fd, ptr, msg, dig); buf[0] = '\0'; if (sighp) @@ -778,7 +804,7 @@ if (Fstat(fd, st) < 0) { (void) snprintf(buf, sizeof(buf), - _("sigh stat: BAD, Fstat(2) failed")); + _("%sstat: BAD, Fstat(2) failed"), origin); goto exit; } @@ -786,7 +812,8 @@ startoff = fd->stats->ops[FDSTAT_READ].bytes; if ((xx = (int) timedRead(fd, (char *)block, sizeof(block))) != (int) sizeof(block)) { (void) snprintf(buf, sizeof(buf), - _("sigh size(%d): BAD, read returned %d"), (int)sizeof(block), xx); + _("%ssize(%d): BAD, read returned %d"), + origin, (int)sizeof(block), xx); goto exit; } @@ -797,7 +824,9 @@ if (memcmp(block, hmagic, nmagic)) { unsigned char * x = (unsigned char *)block; - (void) snprintf(buf, sizeof(buf), _("sigh magic: BAD, read %02x%02x%02x%02x%02x%02x%02x%02x"), x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]); + (void) snprintf(buf, sizeof(buf), + _("%smagic: BAD, read %02x%02x%02x%02x%02x%02x%02x%02x"), + origin, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]); goto exit; } } @@ -806,7 +835,8 @@ il = (rpmuint32_t) ntohl(block[2]); if (il > (st->st_size - startoff - sizeof(block)) || il < 2 || il > 16) { (void) snprintf(buf, sizeof(buf), - _("sigh tags: BAD, no. of tags(%u) out of range"), (unsigned) il); + _("%stags: BAD, no. of tags(%u) out of range"), + origin, (unsigned) il); goto exit; } /* XXX arbitrary max limit check doesn't help much */ @@ -814,19 +844,21 @@ dl = (rpmuint32_t) ntohl(block[3]); if (dl > (st->st_size - startoff - sizeof(block)) || dl < (4+16) || dl > 8192) { (void) snprintf(buf, sizeof(buf), - _("sigh data: BAD, no. of bytes(%u) out of range"), (unsigned) dl); + _("%sdata: BAD, no. of bytes(%u) out of range"), + origin, (unsigned) dl); goto exit; } nb = (il * sizeof(struct entryInfo_s)) + dl; if (nb > (st->st_size - startoff - sizeof(block))) { (void) snprintf(buf, sizeof(buf), - _("hdr blob: BAD, header size (%u) larger than file size"), - (unsigned) nb); + _("%sblob: BAD, header size (%u) larger than file size"), + origin, (unsigned) nb); goto exit; } + + pvlen = (sizeof(il) + sizeof(dl) + nb); if (map) { - size_t pvlen = (sizeof(il) + sizeof(dl) + nb); static const int prot = PROT_READ | PROT_WRITE; static const int flags = MAP_PRIVATE| MAP_ANONYMOUS; static const int fdno = -1; @@ -841,20 +873,18 @@ errno, strerror(errno)); } else { - size_t pvlen = (sizeof(il) + sizeof(dl) + nb); ei = (rpmuint32_t *) xmalloc(pvlen); } if ((xx = (int) timedRead(fd, (char *)&ei[2], nb)) != (int) nb) { (void) snprintf(buf, sizeof(buf), - _("sigh blob(%u): BAD, read returned %d"), (unsigned) nb, xx); + _("%sblob(%u): BAD, read returned %d"), origin, (unsigned) nb, xx); goto exit; } ei[0] = block[2]; ei[1] = block[3]; if (map) { - size_t pvlen = (sizeof(il) + sizeof(dl) + nb); if (mprotect(ei, pvlen, PROT_READ) != 0) fprintf(stderr, "==> mprotect(%p[%u],0x%x) error(%d): %s\n", ei, (unsigned)pvlen, PROT_READ, @@ -912,6 +942,7 @@ if (xx != -1 || !(entry->info.tag == RPMTAG_HEADERSIGNATURES && entry->info.type == REGION_TAG_TYPE + && entry->info.offset > 0 && entry->info.count == (rpmTagCount)REGION_TAG_COUNT)) { (void) snprintf(buf, sizeof(buf), @@ -934,14 +965,14 @@ xx = headerVerifyInfo(il-1, dl, pe+1, &entry->info, 0); if (xx != -1) { (void) snprintf(buf, sizeof(buf), - _("sigh tag[%d]: BAD, %s"), xx, entryInfoStr(&entry->info)); + _("%stag[%d]: BAD, %s"), origin, xx, entryInfoStr(&entry->info)); goto exit; } /* OK, blob looks sane, load the header. */ sigh = headerLoad(ei); if (sigh == NULL) { - (void) snprintf(buf, sizeof(buf), _("sigh load: BAD")); + (void) snprintf(buf, sizeof(buf), _("%sload: BAD"), origin); goto exit; } if (map) { @@ -958,7 +989,7 @@ if (pad && (xx = (int) timedRead(fd, (char *)block, pad)) != (int) pad) { (void) snprintf(buf, sizeof(buf), - _("sigh pad(%u): BAD, read %d bytes"), (unsigned) pad, xx); + _("%spad(%u): BAD, read %d bytes"), origin, (unsigned) pad, xx); goto exit; } @@ -967,28 +998,226 @@ xx = headerGet(sigh, he, HEADERGET_SIGHEADER); if (xx) { size_t datasize = he->p.ui32p[0]; + he->p.ptr = _free(he->p.ptr); rc = printSize(fd, sigSize, pad, datasize, st); - if (rc != RPMRC_OK) + if (rc != RPMRC_OK) { (void) snprintf(buf, sizeof(buf), - _("sigh size(%u): BAD, file length check failed"), - (unsigned) sigSize); + _("%ssize(%u): BAD, file length check failed"), + origin, (unsigned) sigSize); + goto exit; + } + } else { + (void) snprintf(buf, sizeof(buf), + _("%stag(%u): BAD, missing tag"), origin, he->tag); + he->p.ptr = _free(he->p.ptr); + rc = RPMRC_FAIL; + goto exit; } + + he->tag = (rpmTag) RPMSIGTAG_SHA1; + xx = headerGet(sigh, he, HEADERGET_SIGHEADER); he->p.ptr = _free(he->p.ptr); + if (!xx) { + (void) snprintf(buf, sizeof(buf), + _("%stag(%u): BAD, missing tag"), origin, he->tag); + rc = RPMRC_FAIL; + goto exit; + } } (void) headerSetStartOff(sigh, (rpmuint32_t)startoff); (void) headerSetEndOff(sigh, fd->stats->ops[FDSTAT_READ].bytes); + HeaderIterator hi; + rc = RPMRC_OK; /* assume success */ + + for (hi = headerInit(sigh); + headerNext(hi, he, HEADERGET_SIGHEADER); + he->p.ptr = _free(he->p.ptr)) + { + rpmTagType tagtype; + rpmTagCount tagcount; + rpmuint32_t tagsize; + unsigned checkit; + unsigned savesig; + + tagtype = 0; + tagcount = 0; + tagsize = 0; + checkit = 0; + savesig = 0; + +assert(he->p.ptr != NULL); + switch ((rpmSigTag)he->tag) { + case RPMSIGTAG_GPG: + case RPMSIGTAG_PGP5: + case RPMSIGTAG_PGP: + tagtype = RPM_BIN_TYPE; + checkit = 1; + break; + case RPMSIGTAG_SHA1: + tagtype = RPM_STRING_TYPE; + tagcount = 1; + tagsize = 2 * 160/8 + 1; + checkit = 2; + if (sig == NULL) /* XXX prefer signature over digest */ + savesig = 1; /* XXX saved iff dig != NULL */ + break; + case RPMSIGTAG_MD5: + tagtype = RPM_BIN_TYPE; + tagcount = 128/8; +// tagsize = 128/8; + break; + case RPMSIGTAG_RSA: + case RPMSIGTAG_DSA: + case RPMSIGTAG_ECDSA: + tagtype = RPM_BIN_TYPE; + checkit = 1; +#ifdef NOTYET + savesig = 1; /* XXX saved iff dig != NULL */ +#endif + break; + case RPMSIGTAG_SIZE: + case RPMSIGTAG_PAYLOADSIZE: + tagtype = RPM_UINT32_TYPE; + tagcount = 1; +// tagsize = tagcount * sizeof(rpmuint32_t); + break; +#ifdef REFERENCE + case RPMSIGTAG_LONGSIZE: + case RPMSIGTAG_LONGARCHIVESIZE: + tagtype = RPM_UINT64_TYPE; + tagcount = 1; +// tagsize = tagcount * sizeof(rpmuint64_t); + break; + case RPMSIGTAG_RESERVED: + tagtype = RPM_BIN_TYPE; + break; +#endif + case RPMSIGTAG_PADDING: + tagtype = RPM_BIN_TYPE; + checkit = 3; + break; + default: + continue; + break; + } + + +#ifdef NOTYET + /* XXX needs entry->length: augment HE_t? */ + if (tagsize && entry->length != tagsize) { + (void) snprintf(buf, sizeof(buf), + _("%stag(%u): BAD, invalid size(%u)"), + origin, he->tag, entry->length); + rc = RPMRC_FAIL; + break; + } +#endif + + if (tagcount && he->c != tagcount) { + (void) snprintf(buf, sizeof(buf), + _("%stag(%u): BAD, invalid count(%u)"), + origin, he->tag, he->c); + rc = RPMRC_FAIL; + break; + } + + /* XXX header_internal.c handles type verification. */ + if (tagtype && he->t != tagtype) { + (void) snprintf(buf, sizeof(buf), + _("%stag(%u): BAD, invalid type(%u)"), + origin, he->tag, he->t); + rc = RPMRC_FAIL; + break; + } + + switch (checkit) { + case 1: /* Verify he->c == OpenPGP pgpPktLen. */ + /* XXX todo++: check the entire packet? */ + xx = chkPgpPktLen(origin, he->tag, he->p.ui8p, he->c, pp, + buf, sizeof(buf)); + if (xx != RPMRC_OK) { + rc = RPMRC_FAIL; + break; + } + break; + case 2: /* Verify hex string. */ + { const char * s = he->p.str; + rpmuint32_t ns = 0; + while (ns < tagsize && *s != '\0') { + if (strchr("0123456789abcdefABCDEF", *s) == NULL) + break; + ns++; + s++; + } + if (ns != (tagsize-1) || *s != '\0') { + s = he->p.str; + (void) snprintf(buf, sizeof(buf), + _("%stag(%u): BAD, not hex len(%u) \"%*s\""), + origin, he->tag, ns, ns, s); + rc = RPMRC_FAIL; + break; + } + } break; + case 3: /* Verify all zero's */ + { const rpmuint8_t * b = he->p.ui8p; + rpmuint32_t nb; + for (nb = 0; nb < he->c; nb++) { + if (b[nb] != 0) + break; + } + if (nb < he->c) { + (void) snprintf(buf, sizeof(buf), + _("%stag(%u): BAD, not zero at byte offset(%u)"), + origin, he->tag, nb); + rc = RPMRC_FAIL; + break; + } + } break; + default: + break; + } + if (rc != RPMRC_OK) + break; + + /* XXX saved iff dig != NULL (i.e. fdSetDig(fd) has been done) */ + if (dig && savesig) { + sigtag = he->tag; + sigtype = he->t; + sig = _free(sig); + sig = he->p.ptr; + he->p.ptr = NULL; /* XXX steal the malloc'd data */ + siglen = he->c; + } + + } + he->p.ptr = _free(he->p.ptr); + hi = headerFini(hi); + exit: + + if (rc == RPMRC_OK && dig && sig && siglen > 0) { + (void) pgpSetSig(dig, sigtag, sigtype, sig, siglen); + sig = NULL; /* XXX avoid free */ + } + sig = _free(sig); if (sighp) *sighp = ((sigh && rc == RPMRC_OK) ? headerLink(sigh) : NULL); (void)headerFree(sigh); sigh = NULL; + if (sig) + sig = _free(sig); + dig = pgpDigFree(dig); + if (msg != NULL) { buf[sizeof(buf)-1] = '\0'; *msg = xstrdup(buf); } +if (_pkgio_debug) +fprintf(stderr, "<-- rdSignature(%p, %p, %p) rc %d \"%s\"\n", fd, ptr, msg, rc, *msg); + return rc; } @@ -1042,6 +1271,94 @@ return xx; } +static rpmRC hBlobVerify(const void * uh, pgpDig dig, + indexEntry entry, + const unsigned char * regionEnd, rpmuint32_t ril, + char *b, size_t nb) +{ + rpmuint32_t * ei = (rpmuint32_t *) uh; + rpmuint32_t il = (rpmuint32_t) ntohl(ei[0]); + rpmuint32_t dl = (rpmuint32_t) ntohl(ei[1]); + entryInfo pe = (entryInfo) &ei[2]; + rpmRC rc = RPMRC_FAIL; /* assume failure */ + int xx; +entryInfo info = &entry->info; +const void * sig = pgpGetSig(dig); +size_t siglen = dig->siglen; +pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); +DIGEST_CTX * ctxp = NULL; + + /* Do SHA1 if possible). */ + switch (dig->sigtag) { + case RPMTAG_RSAHEADER: + case RPMTAG_DSAHEADER: + case RPMTAG_ECDSAHEADER: + /* Parse the parameters from the OpenPGP packets that will be needed. */ + xx = chkPgpPktLen("", dig->sigtag, sig, siglen, pp, b, nb); + if (xx != RPMRC_OK) { + rc = RPMRC_FAIL; + goto exit; + } + xx = rpmhkpLoadSignature(NULL, dig, pp); + if (xx < 0) { + (void) snprintf(b, nb, + _("skipping header with unverifiable V%u signature"), + (unsigned) dig->signature.version); + rc = RPMRC_FAIL; + goto exit; + } + + switch (dig->signature.pubkey_algo) { + default: + (void) snprintf(b, nb, + _("skipping header with unknown signature algorithm(%u)\n"), + dig->signature.pubkey_algo); + rc = RPMRC_FAIL; + goto exit; + break; + case PGPPUBKEYALGO_RSA: ctxp = &dig->hrsa; break; + case PGPPUBKEYALGO_DSA: ctxp = &dig->hdsa; break; + case PGPPUBKEYALGO_ECDSA: ctxp = &dig->hecdsa; break; + } + + xx = hBlobDigest(uh, dig, dig->signature.hash_algo, + regionEnd, ril, ctxp); + + break; + case RPMSIGTAG_SHA1: + ctxp = &dig->hdsa; /* XXX dig->hsha? */ + xx = hBlobDigest(uh, dig, PGPHASHALGO_SHA1, + regionEnd, ril, ctxp); + break; + default: + xx = (ril > 0 ? headerVerifyInfo(ril-1, dl, pe+1, info, 0) : -1); + if (xx != -1) { + (void) snprintf(b, nb, + _("tag[%d]: BAD, %s"), + xx, entryInfoStr(info)); + rc = RPMRC_FAIL; + } else { + (void) snprintf(b, nb, "Header sanity check: OK"); + rc = RPMRC_OK; + } + b[nb-1] = '\0'; + goto exit; + break; + } + + b[0] = '\0'; + rc = rpmVerifySignature(dig, b); + +exit: + if (ctxp && *ctxp) { + (void) rpmDigestFinal(*ctxp, NULL, NULL, 0); + *ctxp = NULL; + } + dig->sig = _free(dig->sig); + + return rc; +} + /** * Check header consistency, performing headerGet() the hard way. * @@ -1057,6 +1374,7 @@ */ rpmRC headerCheck(pgpDig dig, const void * uh, size_t uc, const char ** msg) { +static const char origin[] = "hdr "; /* XXX +trailing space */ char buf[8*BUFSIZ]; rpmuint32_t * ei = (rpmuint32_t *) uh; rpmuint32_t il = (rpmuint32_t) ntohl(ei[0]); @@ -1078,7 +1396,6 @@ int xx; rpmuint32_t i; pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); -DIGEST_CTX * ctxp = NULL; if (_pkgio_debug) fprintf(stderr, "--> headerCheck(%p, %p[%u], %p)\n", dig, uh, (unsigned) uc, msg); @@ -1106,9 +1423,9 @@ if (entry->info.tag < RPMTAG_HEADERI18NTABLE) { (void) snprintf(buf, sizeof(buf), _("region tag: BAD, %s"), entryInfoStr(&entry->info)); - } else - rc = RPMRC_NOTFOUND; - goto exit; + goto exit; + } + rc = RPMRC_NOTFOUND; } /* Is the region tag sane? */ @@ -1136,6 +1453,7 @@ if (xx != -1 || !(entry->info.tag == RPMTAG_HEADERIMMUTABLE && entry->info.type == REGION_TAG_TYPE + && entry->info.offset > 0 && entry->info.count == (rpmTagCount)REGION_TAG_COUNT)) { (void) snprintf(buf, sizeof(buf), @@ -1152,6 +1470,31 @@ goto exit; } + /* Fish out the autosign pubkey (if present). */ + memset(info, 0, sizeof(*info)); + for (i = 1; i < (unsigned) il; i++) { + xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0); + if (xx != -1) + continue; + if (entry->info.tag == RPMTAG_PUBKEYS) { + dig->pub = _free(dig->pub); + dig->publen = 0; + { rpmiob iob = rpmiobNew(0); + /* XXX FIXME: assumes first pubkey */ + const unsigned char *s = dataStart + entry->info.offset; + iob = rpmiobAppend(iob, (char *)s, 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; + } + } + /* Find an appended header-only digest/signature tag. */ for (i = ril; i < (unsigned) il; i++) { static const rpmuint32_t hsigmin = 16; @@ -1165,33 +1508,33 @@ switch (entry->info.tag) { case RPMTAG_SHA1HEADER: - { const unsigned char * b; - int blen; + { const unsigned char * s; + int ns; if (vsflags & RPMVSF_NOSHA1HEADER) break; if (entry->info.type != RPM_STRING_TYPE || entry->info.count != 1) { (void) snprintf(buf, sizeof(buf), - _("hdr SHA1: BAD, type(%u) != STRING count(%u) != 1"), - entry->info.type, entry->info.count); + _("%sSHA1: BAD, type(%u) != STRING count(%u) != 1"), + origin, entry->info.type, entry->info.count); goto exit; } - blen = 0; - for (b = dataStart + entry->info.offset; *b != '\0'; b++) { - if (strchr("0123456789abcdefABCDEF", *b) == NULL) + ns = 0; + for (s = dataStart + entry->info.offset; *s != '\0'; s++) { + if (strchr("0123456789abcdefABCDEF", *s) == NULL) break; - blen++; + ns++; } - if (*b != '\0' || blen != 40) { - b = dataStart + entry->info.offset; + if (*s != '\0' || ns != 40) { + s = dataStart + entry->info.offset; (void) snprintf(buf, sizeof(buf), - _("hdr SHA1: BAD, not hex off(%d) len(%u) \"%*s\""), - entry->info.offset, blen, blen, b); + _("%sSHA1: BAD, not hex off(%d) len(%u) \"%*s\""), + origin, entry->info.offset, ns, ns, s); goto exit; } if (info->tag == 0) { *info = entry->info; /* structure assignment */ - siglen = blen + 1; + siglen = ns + 1; } } break; case RPMTAG_RSAHEADER: @@ -1201,16 +1544,15 @@ || (entry->info.count < hsigmin || entry->info.count > hsigmax)) { (void) snprintf(buf, sizeof(buf), - _("hdr RSA: BAD, type(%u) != BINARY count(%u) != [%u,%u]"), - entry->info.type, entry->info.count, hsigmin, hsigmax); + _("%sRSA: BAD, type(%u) != BINARY count(%u) != [%u,%u]"), + origin, entry->info.type, entry->info.count, hsigmin, hsigmax); goto exit; } sig = dataStart + entry->info.offset; - xx = pgpPktLen((const rpmuint8_t *)sig, hsigmax, pp); - if (xx < 0 || xx != (int)entry->info.count) { - (void) snprintf(buf, sizeof(buf), - _("hdr RSA: BAD, count(%u) != pktlen(%u)"), - entry->info.count, xx); + xx = chkPgpPktLen(origin, entry->info.tag, + sig, entry->info.count, pp, buf, sizeof(buf)); + if (xx != RPMRC_OK) { + rc = RPMRC_FAIL; goto exit; } *info = entry->info; /* structure assignment */ @@ -1223,16 +1565,15 @@ || (entry->info.count < hsigmin || entry->info.count > hsigmax)) { (void) snprintf(buf, sizeof(buf), - _("hdr DSA: BAD, type(%u) != BINARY count(%u) != [%u,%u]"), - entry->info.type, entry->info.count, hsigmin, hsigmax); + _("%sDSA: BAD, type(%u) != BINARY count(%u) != [%u,%u]"), + origin, entry->info.type, entry->info.count, hsigmin, hsigmax); goto exit; } sig = dataStart + entry->info.offset; - xx = pgpPktLen((const rpmuint8_t *)sig, hsigmax, pp); - if (xx < 0 || xx != (int)entry->info.count) { - (void) snprintf(buf, sizeof(buf), - _("hdr DSA: BAD, count(%u) != pktlen(%u)"), - entry->info.count, xx); + xx = chkPgpPktLen(origin, entry->info.tag, + sig, entry->info.count, pp, buf, sizeof(buf)); + if (xx != RPMRC_OK) { + rc = RPMRC_FAIL; goto exit; } *info = entry->info; /* structure assignment */ @@ -1245,16 +1586,15 @@ || (entry->info.count < hsigmin || entry->info.count > hsigmax)) { (void) snprintf(buf, sizeof(buf), - _("hdr ECDSA: BAD, type(%u) != BINARY count(%u) != [%u,%u]"), - entry->info.type, entry->info.count, hsigmin, hsigmax); + _("%sECDSA: BAD, type(%u) != BINARY count(%u) != [%u,%u]"), + origin, entry->info.type, entry->info.count, hsigmin, hsigmax); goto exit; } sig = dataStart + entry->info.offset; - xx = pgpPktLen((const rpmuint8_t *)sig, hsigmax, pp); - if (xx < 0 || xx != (int)entry->info.count) { - (void) snprintf(buf, sizeof(buf), - _("hdr ECDSA: BAD, count(%u) != pktlen(%u)"), - entry->info.count, xx); + xx = chkPgpPktLen(origin, entry->info.tag, + sig, entry->info.count, pp, buf, sizeof(buf)); + if (xx != RPMRC_OK) { + rc = RPMRC_FAIL; goto exit; } *info = entry->info; /* structure assignment */ @@ -1267,102 +1607,37 @@ rc = RPMRC_NOTFOUND; exit: - /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */ - if (rc != RPMRC_NOTFOUND) { - buf[sizeof(buf)-1] = '\0'; - if (msg) *msg = xstrdup(buf); -if (_pkgio_debug) -fprintf(stderr, "<-- headerCheck#1: rc %d \"%s\"\n", rc, (msg ? *msg: "")); - return rc; - } - /* If no header-only digest/signature, then do simple sanity check. */ - if (info->tag == 0) { - xx = (ril > 0 ? headerVerifyInfo(ril-1, dl, pe+1, &entry->info, 0) : -1); - if (xx != -1) { - (void) snprintf(buf, sizeof(buf), - _("tag[%d]: BAD, %s"), xx, entryInfoStr(&entry->info)); - rc = RPMRC_FAIL; - } else { - (void) snprintf(buf, sizeof(buf), "Header sanity check: OK"); - rc = RPMRC_OK; - } - buf[sizeof(buf)-1] = '\0'; - if (msg) *msg = xstrdup(buf); -if (_pkgio_debug) -fprintf(stderr, "<-- headerCheck#2: rc %d \"%s\"\n", rc, (msg ? *msg: "")); - return rc; - } + switch (rc) { + case RPMRC_OK: + case RPMRC_FAIL: + default: + break; + case RPMRC_NOTFOUND: + /* Verify header-only digest/signature (or sanity check). */ + if (ril == 0) + ril = il; + if (regionEnd == NULL) + regionEnd = ((const unsigned char *)uh) + uc; - /* Verify header-only digest/signature. */ assert(dig != NULL); - dig->nbytes = 0; - - sig = memcpy(xmalloc(siglen), dataStart + info->offset, siglen); - { - const void * osig = pgpGetSig(dig); - osig = _free(osig); - (void) pgpSetSig(dig, info->tag, info->type, sig, info->count); - } - - /* Verify header signatures/digests. */ - switch (info->tag) { - case RPMTAG_RSAHEADER: - case RPMTAG_DSAHEADER: - case RPMTAG_ECDSAHEADER: - /* Parse the parameters from the OpenPGP packets that will be needed. */ - xx = pgpPktLen((const rpmuint8_t *)sig, info->count, pp); - if (xx < 0) { - (void) snprintf(buf, sizeof(buf), - _("skipping header with malformed signature packet")); - rc = RPMRC_FAIL; - goto exit3; - } - xx = rpmhkpLoadSignature(NULL, dig, pp); - if (xx < 0) { - (void) snprintf(buf, sizeof(buf), - _("skipping header with unverifiable V%u signature"), - (unsigned) dig->signature.version); - rc = RPMRC_FAIL; - goto exit3; - } + dig->nbytes = 0; - switch (dig->signature.pubkey_algo) { - default: - (void) snprintf(buf, sizeof(buf), - _("skipping header with unknown signature algorithm(%u)\n"), - dig->signature.pubkey_algo); - rc = RPMRC_FAIL; - goto exit3; - break; - case PGPPUBKEYALGO_RSA: ctxp = &dig->hrsa; break; - case PGPPUBKEYALGO_DSA: ctxp = &dig->hdsa; break; - case PGPPUBKEYALGO_ECDSA: ctxp = &dig->hecdsa; break; + /* Add signature info for an appended tag. */ + if (siglen && dig->sigtag == 0) { + sig = memcpy(xmalloc(siglen), dataStart + info->offset, siglen); + (void) pgpSetSig(dig, info->tag, info->type, sig, siglen); } - xx = hBlobDigest(uh, dig, dig->signature.hash_algo, - regionEnd, ril, ctxp); - - break; - case RPMTAG_SHA1HEADER: - /* XXX dig->hsha? */ - xx = hBlobDigest(uh, dig, PGPHASHALGO_SHA1, - regionEnd, ril, &dig->hdsa); - break; - default: - sig = _free(sig); + rc = hBlobVerify(uh, dig, entry, regionEnd, ril, buf, sizeof(buf)); break; } - buf[0] = '\0'; - rc = rpmVerifySignature(dig, buf); - -exit3: buf[sizeof(buf)-1] = '\0'; if (msg) *msg = xstrdup(buf); if (_pkgio_debug) -fprintf(stderr, "<-- headerCheck #3: rc %d \"%s\"\n", rc, (msg ? *msg: "")); +fprintf(stderr, "<-- headerCheck#3: rc %d \"%s\"\n", rc, (msg ? *msg: "")); return rc; } @@ . ______________________________________________________________________ RPM Package Manager http://rpm5.org CVS Sources Repository rpm-cvs@rpm5.org