Sanitize python object -> tag number exception handling
[platform/upstream/rpm.git] / lib / rpmchecksig.c
1 /** \ingroup rpmcli
2  * \file lib/rpmchecksig.c
3  * Verify the signature of a package.
4  */
5
6 #include "system.h"
7
8 #include <rpm/rpmlib.h>                 /* RPMSIGTAG & related */
9 #include <rpm/rpmpgp.h>
10 #include <rpm/rpmcli.h>
11 #include <rpm/rpmfileutil.h>    /* rpmMkTemp() */
12 #include <rpm/rpmdb.h>
13 #include <rpm/rpmts.h>
14 #include <rpm/rpmlog.h>
15 #include <rpm/rpmstring.h>
16 #include <rpm/rpmkeyring.h>
17
18 #include "rpmio/digest.h"
19 #include "lib/rpmlead.h"
20 #include "lib/signature.h"
21
22 #include "debug.h"
23
24 int _print_pkts = 0;
25
26 static int closeFile(FD_t *fdp)
27 {
28     if (fdp == NULL || *fdp == NULL)
29         return 1;
30
31     /* close and reset *fdp to NULL */
32     (void) Fclose(*fdp);
33     *fdp = NULL;
34     return 0;
35 }
36
37 /**
38  */
39 static int manageFile(FD_t *fdp, const char *fn, int flags)
40 {
41     FD_t fd;
42
43     if (fdp == NULL || fn == NULL)      /* programmer error */
44         return 1;
45
46     /* open a file and set *fdp */
47     if (*fdp == NULL && fn != NULL) {
48         fd = Fopen(fn, (flags & O_ACCMODE) == O_WRONLY ? "w.ufdio" : "r.ufdio");
49         if (fd == NULL || Ferror(fd)) {
50             rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), fn,
51                 Fstrerror(fd));
52             return 1;
53         }
54         *fdp = fd;
55         return 0;
56     }
57
58     /* no operation */
59     if (*fdp != NULL && fn != NULL)
60         return 0;
61
62     /* XXX never reached */
63     return 1;
64 }
65
66 /**
67  * Copy header+payload, calculating digest(s) on the fly.
68  */
69 static int copyFile(FD_t *sfdp, const char *sfnp,
70                 FD_t *tfdp, const char *tfnp)
71 {
72     unsigned char buf[BUFSIZ];
73     ssize_t count;
74     int rc = 1;
75
76     if (manageFile(sfdp, sfnp, O_RDONLY))
77         goto exit;
78     if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC))
79         goto exit;
80
81     while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
82     {
83         if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) {
84             rpmlog(RPMLOG_ERR, _("%s: Fwrite failed: %s\n"), tfnp,
85                 Fstrerror(*tfdp));
86             goto exit;
87         }
88     }
89     if (count < 0) {
90         rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), sfnp, Fstrerror(*sfdp));
91         goto exit;
92     }
93     if (Fflush(*tfdp) != 0) {
94         rpmlog(RPMLOG_ERR, _("%s: Fflush failed: %s\n"), tfnp,
95             Fstrerror(*tfdp));
96     }
97
98     rc = 0;
99
100 exit:
101     if (*sfdp)  (void) closeFile(sfdp);
102     if (*tfdp)  (void) closeFile(tfdp);
103     return rc;
104 }
105
106 /**
107  * Retrieve signer fingerprint from an OpenPGP signature tag.
108  * @param sig           signature header
109  * @param sigtag        signature tag
110  * @retval signid       signer fingerprint
111  * @return              0 on success
112  */
113 static int getSignid(Header sig, rpmSigTag sigtag, pgpKeyID_t signid)
114 {
115     struct rpmtd_s pkt;
116     int rc = 1;
117
118     if (headerGet(sig, sigtag, &pkt, HEADERGET_DEFAULT) && pkt.data != NULL) {
119         pgpDig dig = pgpNewDig();
120
121         if (!pgpPrtPkts(pkt.data, pkt.count, dig, 0)) {
122             memcpy(signid, dig->signature.signid, sizeof(dig->signature.signid));
123             rc = 0;
124         }
125      
126         dig = pgpFreeDig(dig);
127         rpmtdFreeData(&pkt);
128     }
129     return rc;
130 }
131
132 /** \ingroup rpmcli
133  * Create/modify elements in signature header.
134  * @param ts            transaction set
135  * @param qva           mode flags and parameters
136  * @param argv          array of package file names (NULL terminated)
137  * @return              0 on success, -1 on error
138  */
139 static int rpmReSign(rpmts ts, QVA_t qva, ARGV_const_t argv)
140 {
141     FD_t fd = NULL;
142     FD_t ofd = NULL;
143     rpmlead lead;
144     rpmSigTag sigtag;
145     const char *rpm;
146     char *sigtarget = NULL, *trpm = NULL;
147     Header sigh = NULL;
148     char * msg;
149     int res = -1; /* assume failure */
150     int deleting = (qva->qva_mode == RPMSIGN_DEL_SIGNATURE);
151     int xx;
152     
153     if (argv)
154     while ((rpm = *argv++) != NULL)
155     {
156         rpmRC rc;
157         struct rpmtd_s utd;
158
159         fprintf(stdout, "%s:\n", rpm);
160
161         if (manageFile(&fd, rpm, O_RDONLY))
162             goto exit;
163
164         lead = rpmLeadNew();
165
166         if ((rc = rpmLeadRead(fd, lead)) == RPMRC_OK) {
167             const char *lmsg = NULL;
168             rc = rpmLeadCheck(lead, &lmsg);
169             if (rc != RPMRC_OK) 
170                 rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, lmsg);
171         }
172
173         if (rc != RPMRC_OK) {
174             lead = rpmLeadFree(lead);
175             goto exit;
176         }
177
178         msg = NULL;
179         rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
180         switch (rc) {
181         default:
182             rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm,
183                         (msg && *msg ? msg : "\n"));
184             msg = _free(msg);
185             goto exit;
186             break;
187         case RPMRC_OK:
188             if (sigh == NULL) {
189                 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), rpm);
190                 goto exit;
191             }
192             break;
193         }
194         msg = _free(msg);
195
196         /* ASSERT: ofd == NULL && sigtarget == NULL */
197         ofd = rpmMkTempFile(NULL, &sigtarget);
198         if (ofd == NULL || Ferror(ofd)) {
199             rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
200             goto exit;
201         }
202         /* Write the header and archive to a temp file */
203         if (copyFile(&fd, rpm, &ofd, sigtarget))
204             goto exit;
205         /* Both fd and ofd are now closed. sigtarget contains tempfile name. */
206         /* ASSERT: fd == NULL && ofd == NULL */
207
208         /* Dump the immutable region (if present). */
209         if (headerGet(sigh, RPMTAG_HEADERSIGNATURES, &utd, HEADERGET_DEFAULT)) {
210             HeaderIterator hi;
211             struct rpmtd_s copytd;
212             Header oh;
213             Header nh;
214
215             nh = headerNew();
216             if (nh == NULL) {
217                 rpmtdFreeData(&utd);
218                 goto exit;
219             }
220
221             oh = headerCopyLoad(utd.data);
222             hi = headerInitIterator(oh);
223             for (hi = headerInitIterator(oh);
224                 headerNext(hi, &copytd);
225                 rpmtdFreeData(&copytd))
226             {
227                 if (copytd.data)
228                     xx = headerPut(nh, &copytd, HEADERPUT_DEFAULT);
229             }
230             hi = headerFreeIterator(hi);
231             oh = headerFree(oh);
232
233             sigh = headerFree(sigh);
234             sigh = headerLink(nh);
235             nh = headerFree(nh);
236         }
237
238         /* Eliminate broken digest values. */
239         xx = headerDel(sigh, RPMSIGTAG_BADSHA1_1);
240         xx = headerDel(sigh, RPMSIGTAG_BADSHA1_2);
241
242         /* Toss and recalculate header+payload size and digests. */
243         {
244             rpmSigTag const sigs[] = {  RPMSIGTAG_SIZE, 
245                                         RPMSIGTAG_MD5,
246                                         RPMSIGTAG_SHA1,
247                                      };
248             int nsigs = sizeof(sigs) / sizeof(rpmSigTag);
249             for (int i = 0; i < nsigs; i++) {
250                 (void) headerDel(sigh, sigs[i]);
251                 if (rpmAddSignature(sigh, sigtarget, sigs[i], qva->passPhrase))
252                     goto exit;
253             }
254         }
255
256         if (deleting) { /* Nuke all the signature tags. */
257             xx = headerDel(sigh, RPMSIGTAG_GPG);
258             xx = headerDel(sigh, RPMSIGTAG_DSA);
259             xx = headerDel(sigh, RPMSIGTAG_PGP5);
260             xx = headerDel(sigh, RPMSIGTAG_PGP);
261             xx = headerDel(sigh, RPMSIGTAG_RSA);
262         } else          /* If gpg/pgp is configured, replace the signature. */
263         if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
264             pgpKeyID_t oldsignid, newsignid;
265
266             /* Grab the old signature fingerprint (if any) */
267             memset(oldsignid, 0, sizeof(oldsignid));
268             xx = getSignid(sigh, sigtag, oldsignid);
269
270             switch (sigtag) {
271             case RPMSIGTAG_DSA:
272                 xx = headerDel(sigh, RPMSIGTAG_GPG);
273                 break;
274             case RPMSIGTAG_RSA:
275                 xx = headerDel(sigh, RPMSIGTAG_PGP);
276                 break;
277             case RPMSIGTAG_GPG:
278                 xx = headerDel(sigh, RPMSIGTAG_DSA);
279             case RPMSIGTAG_PGP5:
280             case RPMSIGTAG_PGP:
281                 xx = headerDel(sigh, RPMSIGTAG_RSA);
282                 break;
283             default:
284                 break;
285             }
286
287             xx = headerDel(sigh, sigtag);
288             if (rpmAddSignature(sigh, sigtarget, sigtag, qva->passPhrase)) {
289                 goto exit;
290             }
291
292             /* If package was previously signed, check for same signer. */
293             memset(newsignid, 0, sizeof(newsignid));
294             if (memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
295
296                 /* Grab the new signature fingerprint */
297                 xx = getSignid(sigh, sigtag, newsignid);
298
299                 /* If same signer, skip resigning the package. */
300                 if (!memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
301
302                     char *signid = pgpHexStr(newsignid+4, sizeof(newsignid)-4);
303                     rpmlog(RPMLOG_WARNING,
304                         _("%s: was already signed by key ID %s, skipping\n"),
305                         rpm, signid);
306                     free(signid);
307
308                     /* Clean up intermediate target */
309                     xx = unlink(sigtarget);
310                     sigtarget = _free(sigtarget);
311                     continue;
312                 }
313             }
314         }
315
316         /* Reallocate the signature into one contiguous region. */
317         sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
318         if (sigh == NULL)       /* XXX can't happen */
319             goto exit;
320
321         rasprintf(&trpm, "%s.XXXXXX", rpm);
322         ofd = rpmMkTemp(trpm);
323         if (ofd == NULL || Ferror(ofd)) {
324             rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
325             goto exit;
326         }
327
328         /* Write the lead/signature of the output rpm */
329         rc = rpmLeadWrite(ofd, lead);
330         lead = rpmLeadFree(lead);
331         if (rc != RPMRC_OK) {
332             rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,
333                 Fstrerror(ofd));
334             goto exit;
335         }
336
337         if (rpmWriteSignature(ofd, sigh)) {
338             rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm,
339                 Fstrerror(ofd));
340             goto exit;
341         }
342
343         /* Append the header and archive from the temp file */
344         /* ASSERT: fd == NULL && ofd != NULL */
345         if (copyFile(&fd, sigtarget, &ofd, trpm))
346             goto exit;
347         /* Both fd and ofd are now closed. */
348         /* ASSERT: fd == NULL && ofd == NULL */
349
350         /* Move final target into place, restore file permissions. */
351         {
352             struct stat st;
353             xx = stat(rpm, &st);
354             xx = unlink(rpm);
355             xx = rename(trpm, rpm);
356             xx = chmod(rpm, st.st_mode);
357         }
358         trpm = _free(trpm);
359
360         /* Clean up intermediate target */
361         xx = unlink(sigtarget);
362         sigtarget = _free(sigtarget);
363     }
364
365     res = 0;
366
367 exit:
368     if (fd)     (void) closeFile(&fd);
369     if (ofd)    (void) closeFile(&ofd);
370
371     sigh = rpmFreeSignature(sigh);
372
373     if (sigtarget) {
374         xx = unlink(sigtarget);
375         sigtarget = _free(sigtarget);
376     }
377     if (trpm) {
378         (void) unlink(trpm);
379         free(trpm);
380     }
381
382     return res;
383 }
384
385 /** \ingroup rpmcli
386  * Import public key(s).
387  * @todo Implicit --update policy for gpg-pubkey headers.
388  * @param ts            transaction set
389  * @param qva           mode flags and parameters
390  * @param argv          array of pubkey file names (NULL terminated)
391  * @return              0 on success
392  */
393 static int rpmcliImportPubkeys(const rpmts ts, QVA_t qva, ARGV_const_t argv)
394 {
395     const char * fn;
396     unsigned char * pkt = NULL;
397     size_t pktlen = 0;
398     char * t = NULL;
399     int res = 0;
400     rpmRC rpmrc;
401     int rc;
402
403     if (argv == NULL) return res;
404
405     while ((fn = *argv++) != NULL) {
406
407         rpmtsClean(ts);
408         pkt = _free(pkt);
409         t = _free(t);
410
411         /* If arg looks like a keyid, then attempt keyserver retrieve. */
412         if (fn[0] == '0' && fn[1] == 'x') {
413             const char * s;
414             int i;
415             for (i = 0, s = fn+2; *s && isxdigit(*s); s++, i++)
416                 {};
417             if (i == 8 || i == 16) {
418                 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
419                 if (t && *t != '%')
420                     fn = t;
421             }
422         }
423
424         /* Read pgp packet. */
425         if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
426             rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, rc);
427             res++;
428             continue;
429         }
430         if (rc != PGPARMOR_PUBKEY) {
431             rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn);
432             res++;
433             continue;
434         }
435
436         /* Import pubkey packet(s). */
437         if ((rpmrc = rpmtsImportPubkey(ts, pkt, pktlen)) != RPMRC_OK) {
438             rpmlog(RPMLOG_ERR, _("%s: import failed.\n"), fn);
439             res++;
440             continue;
441         }
442
443     }
444     
445 rpmtsClean(ts);
446     pkt = _free(pkt);
447     t = _free(t);
448     return res;
449 }
450
451 /**
452  * @todo If the GPG key was known available, the md5 digest could be skipped.
453  */
454 static int readFile(FD_t fd, const char * fn, pgpDig dig,
455                     rpmDigestBundle plbundle, rpmDigestBundle hdrbundle)
456 {
457     unsigned char buf[4*BUFSIZ];
458     ssize_t count;
459     int rc = 1;
460     Header h = NULL;
461
462     /* Read the header from the package. */
463     if ((h = headerRead(fd, HEADER_MAGIC_YES)) == NULL) {
464         rpmlog(RPMLOG_ERR, _("%s: headerRead failed\n"), fn);
465         goto exit;
466     }
467
468     if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
469         struct rpmtd_s utd;
470     
471         if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)){
472             rpmlog(RPMLOG_ERR, 
473                     _("%s: Immutable header region could not be read. "
474                     "Corrupted package?\n"), fn);
475             goto exit;
476         }
477         rpmDigestBundleUpdate(hdrbundle, rpm_header_magic, sizeof(rpm_header_magic));
478         rpmDigestBundleUpdate(hdrbundle, utd.data, utd.count);
479         rpmtdFreeData(&utd);
480     }
481
482     /* Read the payload from the package. */
483     while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
484     if (count < 0) {
485         rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
486         goto exit;
487     }
488
489     rc = 0;
490
491 exit:
492     headerFree(h);
493     return rc;
494 }
495
496 /* Parse the parameters from the OpenPGP packets that will be needed. */
497 /* XXX TODO: unify with similar parsePGP() in package.c */
498 static rpmRC parsePGP(rpmtd sigtd, const char *fn, pgpDig dig)
499 {
500     rpmRC rc = RPMRC_FAIL;
501     int debug = (_print_pkts & rpmIsDebug());
502     if ((pgpPrtPkts(sigtd->data, sigtd->count, dig, debug) == 0) &&
503          (dig->signature.version == 3 || dig->signature.version == 4)) {
504         rc = RPMRC_OK;
505     } else {
506         rpmlog(RPMLOG_ERR,
507             _("skipping package %s with unverifiable V%u signature\n"), fn,
508             dig->signature.version);
509     }
510     return rc;
511 }
512
513 /* 
514  * Figure best available signature. 
515  * XXX TODO: Similar detection in rpmReadPackageFile(), unify these.
516  */
517 static rpmSigTag bestSig(Header sigh, int nosignatures, int nodigests)
518 {
519     rpmSigTag sigtag = 0;
520     if (sigtag == 0 && !nosignatures) {
521         if (headerIsEntry(sigh, RPMSIGTAG_DSA))
522             sigtag = RPMSIGTAG_DSA;
523         else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
524             sigtag = RPMSIGTAG_RSA;
525         else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
526             sigtag = RPMSIGTAG_GPG;
527         else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
528             sigtag = RPMSIGTAG_PGP;
529     }
530     if (sigtag == 0 && !nodigests) {
531         if (headerIsEntry(sigh, RPMSIGTAG_MD5))
532             sigtag = RPMSIGTAG_MD5;
533         else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
534             sigtag = RPMSIGTAG_SHA1;    /* XXX never happens */
535     }
536     return sigtag;
537 }
538
539 static const char *sigtagname(rpmSigTag sigtag, int upper)
540 {
541     const char *n = NULL;
542
543     switch (sigtag) {
544     case RPMSIGTAG_SIZE:
545         n = (upper ? "SIZE" : "size");
546         break;
547     case RPMSIGTAG_SHA1:
548         n = (upper ? "SHA1" : "sha1");
549         break;
550     case RPMSIGTAG_MD5:
551         n = (upper ? "MD5" : "md5");
552         break;
553     case RPMSIGTAG_RSA:
554         n = (upper ? "RSA" : "rsa");
555         break;
556     case RPMSIGTAG_PGP5:        /* XXX legacy */
557     case RPMSIGTAG_PGP:
558         n = (upper ? "(MD5) PGP" : "(md5) pgp");
559         break;
560     case RPMSIGTAG_DSA:
561         n = (upper ? "(SHA1) DSA" : "(sha1) dsa");
562         break;
563     case RPMSIGTAG_GPG:
564         n = (upper ? "GPG" : "gpg");
565         break;
566     default:
567         n = (upper ? "?UnknownSigatureType?" : "???");
568         break;
569     }
570     return n;
571 }
572
573 /* 
574  * Format sigcheck result for output, appending the message spew to buf and
575  * bad/missing keyids to keyprob.
576  *
577  * In verbose mode, just dump it all. Otherwise ok signatures
578  * are dumped lowercase, bad sigs uppercase and for PGP/GPG
579  * if misssing/untrusted key it's uppercase in parenthesis
580  * and stash the key id as <SIGTYPE>#<keyid>. Pfft.
581  */
582 static void formatResult(rpmSigTag sigtag, rpmRC sigres, const char *result,
583                          int havekey, char **keyprob, char **buf)
584 {
585     char *msg = NULL;
586     if (rpmIsVerbose()) {
587         rasprintf(&msg, "    %s", result);
588     } else { 
589         /* Check for missing / untrusted keys in result. */
590         const char *signame = sigtagname(sigtag, (sigres != RPMRC_OK));
591         
592         if (havekey && (sigres == RPMRC_NOKEY || sigres == RPMRC_NOTTRUSTED)) {
593             const char *tempKey = strstr(result, "ey ID");
594             if (tempKey) {
595                 char *keyid = strndup(tempKey + 6, 8);
596                 char *idprob = NULL;
597                 rasprintf(&idprob, " %s#%s", signame, keyid);
598                 rstrcat(keyprob, idprob);
599                 free(keyid);
600                 free(idprob);
601             }
602         }
603         rasprintf(&msg, (*keyprob ? "(%s) " : "%s "), signame);
604     }
605     rstrcat(buf, msg);
606     free(msg);
607 }
608
609 static int rpmpkgVerifySigs(rpmKeyring keyring, rpmQueryFlags flags,
610                            FD_t fd, const char *fn)
611 {
612
613     char *buf = NULL;
614     char *missingKeys = NULL; 
615     char *untrustedKeys = NULL;
616     struct rpmtd_s sigtd;
617     rpmTag sigtag;
618     pgpDig dig = NULL;
619     pgpDigParams sigp;
620     Header sigh = NULL;
621     HeaderIterator hi = NULL;
622     char * msg = NULL;
623     int res = 1; /* assume failure */
624     int xx;
625     rpmRC rc;
626     int failed = 0;
627     int nodigests = !(flags & VERIFY_DIGEST);
628     int nosignatures = !(flags & VERIFY_SIGNATURE);
629     rpmDigestBundle plbundle = rpmDigestBundleNew();
630     rpmDigestBundle hdrbundle = rpmDigestBundleNew();
631
632     rpmlead lead = rpmLeadNew();
633     if ((rc = rpmLeadRead(fd, lead)) == RPMRC_OK) {
634         const char *lmsg = NULL;
635         rc = rpmLeadCheck(lead, &lmsg);
636         if (rc != RPMRC_OK) 
637             rpmlog(RPMLOG_ERR, "%s: %s\n", fn, lmsg);
638     }
639     lead = rpmLeadFree(lead);
640
641     if (rc != RPMRC_OK) {
642         goto exit;
643     }
644
645     rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
646     switch (rc) {
647     default:
648         rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
649                     (msg && *msg ? msg : "\n"));
650         msg = _free(msg);
651         goto exit;
652         break;
653     case RPMRC_OK:
654         if (sigh == NULL) {
655             rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
656             goto exit;
657         }
658         break;
659     }
660     msg = _free(msg);
661
662     /* Grab a hint of what needs doing to avoid duplication. */
663     sigtag = bestSig(sigh, nosignatures, nodigests);
664
665     dig = pgpNewDig();
666     sigp = &dig->signature;
667
668     /* XXX RSA needs the hash_algo, so decode early. */
669     if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP ||
670                 sigtag == RPMSIGTAG_DSA || sigtag == RPMSIGTAG_GPG) {
671         xx = headerGet(sigh, sigtag, &sigtd, HEADERGET_DEFAULT);
672         xx = pgpPrtPkts(sigtd.data, sigtd.count, dig, 0);
673         rpmtdFreeData(&sigtd);
674         /* XXX assume same hash_algo in header-only and header+payload */
675         rpmDigestBundleAdd(plbundle, sigp->hash_algo, RPMDIGEST_NONE);
676         rpmDigestBundleAdd(hdrbundle, sigp->hash_algo, RPMDIGEST_NONE);
677     }
678
679     if (headerIsEntry(sigh, RPMSIGTAG_PGP) ||
680                       headerIsEntry(sigh, RPMSIGTAG_PGP5) ||
681                       headerIsEntry(sigh, RPMSIGTAG_MD5)) {
682         rpmDigestBundleAdd(plbundle, PGPHASHALGO_MD5, RPMDIGEST_NONE);
683     }
684     if (headerIsEntry(sigh, RPMSIGTAG_GPG)) {
685         rpmDigestBundleAdd(plbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
686     }
687
688     /* always do sha1 hash of header */
689     rpmDigestBundleAdd(hdrbundle, PGPHASHALGO_SHA1, RPMDIGEST_NONE);
690
691     /* Read the file, generating digest(s) on the fly. */
692     fdSetBundle(fd, plbundle);
693     if (readFile(fd, fn, dig, plbundle, hdrbundle)) {
694         goto exit;
695     }
696
697     rasprintf(&buf, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
698
699     hi = headerInitIterator(sigh);
700     for (; headerNext(hi, &sigtd) != 0; rpmtdFreeData(&sigtd)) {
701         char *result = NULL;
702         int havekey = 0;
703         DIGEST_CTX ctx = NULL;
704         if (sigtd.data == NULL) /* XXX can't happen */
705             continue;
706
707         /* Clean up parameters from previous sigtag. */
708         pgpCleanDig(dig);
709
710         switch (sigtd.tag) {
711         case RPMSIGTAG_GPG:
712         case RPMSIGTAG_PGP5:    /* XXX legacy */
713         case RPMSIGTAG_PGP:
714             havekey = 1;
715         case RPMSIGTAG_RSA:
716         case RPMSIGTAG_DSA:
717             if (nosignatures)
718                  continue;
719             if (parsePGP(&sigtd, fn, dig) != RPMRC_OK) {
720                 goto exit;
721             }
722             ctx = rpmDigestBundleDupCtx(havekey ? plbundle : hdrbundle,
723                                         dig->signature.hash_algo);
724             break;
725         case RPMSIGTAG_SHA1:
726             if (nodigests)
727                  continue;
728             ctx = rpmDigestBundleDupCtx(hdrbundle, PGPHASHALGO_SHA1);
729             break;
730         case RPMSIGTAG_MD5:
731             if (nodigests)
732                  continue;
733             ctx = rpmDigestBundleDupCtx(plbundle, PGPHASHALGO_MD5);
734             break;
735         default:
736             continue;
737             break;
738         }
739
740         rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &result);
741         rpmDigestFinal(ctx, NULL, NULL, 0);
742
743         formatResult(sigtd.tag, rc, result, havekey, 
744                      (rc == RPMRC_NOKEY ? &missingKeys : &untrustedKeys),
745                      &buf);
746         free(result);
747
748         if (rc != RPMRC_OK) {
749             failed = 1;
750         }
751
752     }
753     res = failed;
754
755     if (rpmIsVerbose()) {
756         rpmlog(RPMLOG_NOTICE, "%s", buf);
757     } else {
758         const char *ok = (failed ? _("NOT OK") : _("OK"));
759         rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf, ok,
760                missingKeys ? _(" (MISSING KEYS:") : "",
761                missingKeys ? missingKeys : "",
762                missingKeys ? _(") ") : "",
763                untrustedKeys ? _(" (UNTRUSTED KEYS:") : "",
764                untrustedKeys ? untrustedKeys : "",
765                untrustedKeys ? _(")") : "");
766     }
767     free(missingKeys);
768     free(untrustedKeys);
769
770 exit:
771     free(buf);
772     rpmDigestBundleFree(hdrbundle);
773     rpmDigestBundleFree(plbundle);
774     fdSetBundle(fd, NULL); /* XXX avoid double-free from fd close */
775     sigh = rpmFreeSignature(sigh);
776     hi = headerFreeIterator(hi);
777     pgpFreeDig(dig);
778     return res;
779 }
780
781 /* Wrapper around rpmkVerifySigs to preserve API */
782 int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
783 {
784     int rc = 1; /* assume failure */
785     if (ts && qva && fd && fn) {
786         rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
787         rc = rpmpkgVerifySigs(keyring, qva->qva_flags, fd, fn);
788         rpmKeyringFree(keyring);
789     }
790     return rc;
791 }
792
793 int rpmcliSign(rpmts ts, QVA_t qva, ARGV_const_t argv)
794 {
795     const char * arg;
796     int res = 0;
797     int xx;
798     rpmKeyring keyring = NULL;
799
800     if (argv == NULL) return res;
801
802     switch (qva->qva_mode) {
803     case RPMSIGN_CHK_SIGNATURE:
804         break;
805     case RPMSIGN_IMPORT_PUBKEY:
806         return rpmcliImportPubkeys(ts, qva, argv);
807         break;
808     case RPMSIGN_NEW_SIGNATURE:
809     case RPMSIGN_ADD_SIGNATURE:
810     case RPMSIGN_DEL_SIGNATURE:
811         return rpmReSign(ts, qva, argv);
812         break;
813     case RPMSIGN_NONE:
814     default:
815         return -1;
816         break;
817     }
818
819     keyring = rpmtsGetKeyring(ts, 1);
820     while ((arg = *argv++) != NULL) {
821         FD_t fd;
822
823         fd = Fopen(arg, "r.ufdio");
824         if (fd == NULL || Ferror(fd)) {
825             rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), 
826                      arg, Fstrerror(fd));
827             res++;
828         } else if (rpmpkgVerifySigs(keyring, qva->qva_flags, fd, arg)) {
829             res++;
830         }
831
832         if (fd != NULL) xx = Fclose(fd);
833         rpmdbCheckSignals();
834     }
835     rpmKeyringFree(keyring);
836
837     return res;
838 }