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