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

Reply via email to