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