doxygen cleanup.
[platform/upstream/rpm.git] / lib / signature.c
1 /** \ingroup signature
2  * \file lib/signature.c
3  */
4
5 #include "system.h"
6
7 #include "rpmio_internal.h"
8 #include <rpmlib.h>
9 #include <rpmmacro.h>   /* XXX for rpmGetPath() */
10 #include "rpmdb.h"
11
12 #include "depends.h"
13 #include "misc.h"       /* XXX for dosetenv() and makeTempFile() */
14 #include "legacy.h"     /* XXX for mdbinfile() */
15 #include "rpmlead.h"
16 #include "signature.h"
17 #include "debug.h"
18
19 /*@access rpmTransactionSet@*/
20 /*@access Header@*/             /* XXX compared with NULL */
21 /*@access FD_t@*/               /* XXX compared with NULL */
22 /*@access DIGEST_CTX@*/         /* XXX compared with NULL */
23 /*@access pgpDig@*/
24
25 int rpmLookupSignatureType(int action)
26 {
27     /*@unchecked@*/
28     static int disabled = 0;
29     int rc = 0;
30
31     switch (action) {
32     case RPMLOOKUPSIG_DISABLE:
33         disabled = -2;
34         break;
35     case RPMLOOKUPSIG_ENABLE:
36         disabled = 0;
37         /*@fallthrough@*/
38     case RPMLOOKUPSIG_QUERY:
39         if (disabled)
40             break;      /* Disabled */
41       { const char *name = rpmExpand("%{?_signature}", NULL);
42         if (!(name && *name != '\0'))
43             rc = 0;
44         else if (!xstrcasecmp(name, "none"))
45             rc = 0;
46         else if (!xstrcasecmp(name, "pgp"))
47             rc = RPMSIGTAG_PGP;
48         else if (!xstrcasecmp(name, "pgp5"))    /* XXX legacy */
49             rc = RPMSIGTAG_PGP;
50         else if (!xstrcasecmp(name, "gpg"))
51             rc = RPMSIGTAG_GPG;
52         else
53             rc = -1;    /* Invalid %_signature spec in macro file */
54         name = _free(name);
55       } break;
56     }
57     return rc;
58 }
59
60 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
61 /* executable of the requested version, or NULL when none found. */
62
63 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
64 {
65     /* Actually this should support having more then one pgp version. */
66     /* At the moment only one version is possible since we only       */
67     /* have one %_pgpbin and one %_pgp_path.                          */
68
69     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
70     const char *pgpbin = rpmGetPath("%{?_pgpbin}", NULL);
71
72     if (saved_pgp_version == PGP_UNKNOWN) {
73         char *pgpvbin;
74         struct stat st;
75
76         if (!(pgpbin && pgpbin[0] != '\0')) {
77             pgpbin = _free(pgpbin);
78             saved_pgp_version = -1;
79             return NULL;
80         }
81         pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
82         (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
83
84         if (stat(pgpvbin, &st) == 0)
85             saved_pgp_version = PGP_5;
86         else if (stat(pgpbin, &st) == 0)
87             saved_pgp_version = PGP_2;
88         else
89             saved_pgp_version = PGP_NOTDETECTED;
90     }
91
92     if (pgpVer && pgpbin)
93         *pgpVer = saved_pgp_version;
94     return pgpbin;
95 }
96
97 /**
98  * Check package size.
99  * @todo rpmio: use fdSize rather than fstat(2) to get file size.
100  * @param fd                    package file handle
101  * @param siglen                signature header size
102  * @param pad                   signature padding
103  * @param datalen               length of header+payload
104  * @return                      rpmRC return code
105  */
106 static inline rpmRC checkSize(FD_t fd, int siglen, int pad, int datalen)
107         /*@globals fileSystem @*/
108         /*@modifies fileSystem @*/
109 {
110     struct stat st;
111     rpmRC rc;
112
113     if (fstat(Fileno(fd), &st))
114         return RPMRC_FAIL;
115
116     if (!S_ISREG(st.st_mode)) {
117         rpmMessage(RPMMESS_DEBUG,
118             _("file is not regular -- skipping size check\n"));
119         return RPMRC_OK;
120     }
121
122     /*@-sizeoftype@*/
123     rc = (((sizeof(struct rpmlead) + siglen + pad + datalen) - st.st_size)
124         ? RPMRC_BADSIZE : RPMRC_OK);
125
126     rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_DEBUG),
127         _("Expected size: %12d = lead(%d)+sigs(%d)+pad(%d)+data(%d)\n"),
128                 (int)sizeof(struct rpmlead)+siglen+pad+datalen,
129                 (int)sizeof(struct rpmlead), siglen, pad, datalen);
130     /*@=sizeoftype@*/
131     rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_DEBUG),
132         _("  Actual size: %12d\n"), (int)st.st_size);
133
134     return rc;
135 }
136
137 rpmRC rpmReadSignature(FD_t fd, Header * headerp, sigType sig_type)
138 {
139     byte buf[2048];
140     int sigSize, pad;
141     int_32 type, count;
142     int_32 *archSize;
143     Header h = NULL;
144     rpmRC rc = RPMRC_FAIL;              /* assume failure */
145
146     if (headerp)
147         *headerp = NULL;
148
149     buf[0] = 0;
150     switch (sig_type) {
151     case RPMSIGTYPE_NONE:
152         rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
153         rc = RPMRC_OK;
154         break;
155     case RPMSIGTYPE_PGP262_1024:
156         rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
157         /* These are always 256 bytes */
158         if (timedRead(fd, buf, 256) != 256)
159             break;
160         h = headerNew();
161         (void) headerAddEntry(h, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
162         rc = RPMRC_OK;
163         break;
164     case RPMSIGTYPE_MD5:
165     case RPMSIGTYPE_MD5_PGP:
166         rpmError(RPMERR_BADSIGTYPE,
167               _("Old (internal-only) signature!  How did you get that!?\n"));
168         break;
169     case RPMSIGTYPE_HEADERSIG:
170     case RPMSIGTYPE_DISABLE:
171         /* This is a new style signature */
172         h = headerRead(fd, HEADER_MAGIC_YES);
173         if (h == NULL)
174             break;
175
176         rc = RPMRC_OK;
177         sigSize = headerSizeof(h, HEADER_MAGIC_YES);
178
179         /* XXX Legacy headers have a HEADER_IMAGE tag added. */
180         if (headerIsEntry(h, RPMTAG_HEADERIMAGE))
181             sigSize -= (16 + 16);
182
183         pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
184         if (sig_type == RPMSIGTYPE_HEADERSIG) {
185             if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type,
186                                 (void **)&archSize, &count))
187                 break;
188             rc = checkSize(fd, sigSize, pad, *archSize);
189         }
190         if (pad && timedRead(fd, buf, pad) != pad)
191             rc = RPMRC_SHORTREAD;
192         break;
193     default:
194         break;
195     }
196
197     if (headerp && rc == 0)
198         *headerp = headerLink(h, NULL);
199
200     h = headerFree(h, NULL);
201
202     return rc;
203 }
204
205 int rpmWriteSignature(FD_t fd, Header h)
206 {
207     static byte buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
208     int sigSize, pad;
209     int rc;
210
211     rc = headerWrite(fd, h, HEADER_MAGIC_YES);
212     if (rc)
213         return rc;
214
215     sigSize = headerSizeof(h, HEADER_MAGIC_YES);
216     pad = (8 - (sigSize % 8)) % 8;
217     if (pad) {
218         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
219             rc = 1;
220     }
221     rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
222     return rc;
223 }
224
225 Header rpmNewSignature(void)
226 {
227     Header h = headerNew();
228     return h;
229 }
230
231 Header rpmFreeSignature(Header h)
232 {
233     return headerFree(h, "FreeSignature");
234 }
235
236 /**
237  * Generate PGP (aka RSA/MD5) signature(s) for a header+payload file.
238  * @param file          header+payload file name
239  * @retval pkt          signature packet(s)
240  * @retval pktlen       signature packet(s) length
241  * @param passPhrase    private key pass phrase
242  * @return              0 on success, 1 on failure
243  */
244 static int makePGPSignature(const char * file, /*@out@*/ byte ** pkt,
245                 /*@out@*/ int_32 * pktlen, /*@null@*/ const char * passPhrase)
246         /*@globals errno, rpmGlobalMacroContext, fileSystem @*/
247         /*@modifies errno, *pkt, *pktlen, rpmGlobalMacroContext, fileSystem @*/
248 {
249     char * sigfile = alloca(1024);
250     int pid, status;
251     int inpipe[2];
252     struct stat st;
253     const char * cmd;
254     char *const *av;
255     int rc;
256
257     (void) stpcpy( stpcpy(sigfile, file), ".sig");
258
259     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
260     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
261
262     inpipe[0] = inpipe[1] = 0;
263     (void) pipe(inpipe);
264
265     if (!(pid = fork())) {
266         const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
267         const char *path;
268         pgpVersion pgpVer;
269
270         (void) close(STDIN_FILENO);
271         (void) dup2(inpipe[0], 3);
272         (void) close(inpipe[1]);
273
274         (void) dosetenv("PGPPASSFD", "3", 1);
275         if (pgp_path && *pgp_path != '\0')
276             (void) dosetenv("PGPPATH", pgp_path, 1);
277
278         /* dosetenv("PGPPASS", passPhrase, 1); */
279
280         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
281             switch(pgpVer) {
282             case PGP_2:
283                 cmd = rpmExpand("%{?__pgp_sign_cmd}", NULL);
284                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
285                 if (!rc)
286                     rc = execve(av[0], av+1, environ);
287                 break;
288             case PGP_5:
289                 cmd = rpmExpand("%{?__pgp5_sign_cmd}", NULL);
290                 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
291                 if (!rc)
292                     rc = execve(av[0], av+1, environ);
293                 break;
294             case PGP_UNKNOWN:
295             case PGP_NOTDETECTED:
296                 errno = ENOENT;
297                 break;
298             }
299         }
300         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
301                         strerror(errno));
302         _exit(RPMERR_EXEC);
303     }
304
305     delMacro(NULL, "__plaintext_filename");
306     delMacro(NULL, "__signature_filename");
307
308     (void) close(inpipe[0]);
309     if (passPhrase)
310         (void) write(inpipe[1], passPhrase, strlen(passPhrase));
311     (void) write(inpipe[1], "\n", 1);
312     (void) close(inpipe[1]);
313
314     (void)waitpid(pid, &status, 0);
315     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
316         rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
317         return 1;
318     }
319
320     if (stat(sigfile, &st)) {
321         /* PGP failed to write signature */
322         if (sigfile) (void) unlink(sigfile);  /* Just in case */
323         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
324         return 1;
325     }
326
327     *pktlen = st.st_size;
328     rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *pktlen);
329     *pkt = xmalloc(*pktlen);
330
331     {   FD_t fd;
332
333         rc = 0;
334         fd = Fopen(sigfile, "r.fdio");
335         if (fd != NULL && !Ferror(fd)) {
336             rc = timedRead(fd, *pkt, *pktlen);
337             if (sigfile) (void) unlink(sigfile);
338             (void) Fclose(fd);
339         }
340         if (rc != *pktlen) {
341             *pkt = _free(*pkt);
342             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
343             return 1;
344         }
345     }
346
347     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *pktlen);
348
349     return 0;
350 }
351
352 /**
353  * Generate GPG (aka DSA) signature(s) for a header+payload file.
354  * @param file          header+payload file name
355  * @retval pkt          signature packet(s)
356  * @retval pktlen       signature packet(s) length
357  * @param passPhrase    private key pass phrase
358  * @return              0 on success, 1 on failure
359  */
360 static int makeGPGSignature(const char * file, /*@out@*/ byte ** pkt,
361                 /*@out@*/ int_32 * pktlen, /*@null@*/ const char * passPhrase)
362         /*@globals rpmGlobalMacroContext, fileSystem @*/
363         /*@modifies *pkt, *pktlen, rpmGlobalMacroContext, fileSystem @*/
364 {
365     char * sigfile = alloca(1024);
366     int pid, status;
367     int inpipe[2];
368     FILE * fpipe;
369     struct stat st;
370     const char * cmd;
371     char *const *av;
372     int rc;
373
374     (void) stpcpy( stpcpy(sigfile, file), ".sig");
375
376     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
377     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
378
379     inpipe[0] = inpipe[1] = 0;
380     (void) pipe(inpipe);
381
382     if (!(pid = fork())) {
383         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
384
385         (void) close(STDIN_FILENO);
386         (void) dup2(inpipe[0], 3);
387         (void) close(inpipe[1]);
388
389         if (gpg_path && *gpg_path != '\0')
390             (void) dosetenv("GNUPGHOME", gpg_path, 1);
391
392         cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
393         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
394         if (!rc)
395             rc = execve(av[0], av+1, environ);
396
397         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
398                         strerror(errno));
399         _exit(RPMERR_EXEC);
400     }
401
402     delMacro(NULL, "__plaintext_filename");
403     delMacro(NULL, "__signature_filename");
404
405     fpipe = fdopen(inpipe[1], "w");
406     (void) close(inpipe[0]);
407     if (fpipe) {
408         fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
409         (void) fclose(fpipe);
410     }
411
412     (void) waitpid(pid, &status, 0);
413     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
414         rpmError(RPMERR_SIGGEN, _("gpg failed\n"));
415         return 1;
416     }
417
418     if (stat(sigfile, &st)) {
419         /* GPG failed to write signature */
420         if (sigfile) (void) unlink(sigfile);  /* Just in case */
421         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
422         return 1;
423     }
424
425     *pktlen = st.st_size;
426     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *pktlen);
427     *pkt = xmalloc(*pktlen);
428
429     {   FD_t fd;
430
431         rc = 0;
432         fd = Fopen(sigfile, "r.fdio");
433         if (fd != NULL && !Ferror(fd)) {
434             rc = timedRead(fd, *pkt, *pktlen);
435             if (sigfile) (void) unlink(sigfile);
436             (void) Fclose(fd);
437         }
438         if (rc != *pktlen) {
439             *pkt = _free(*pkt);
440             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
441             return 1;
442         }
443     }
444
445     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *pktlen);
446
447     return 0;
448 }
449
450 /*@unchecked@*/
451 static unsigned char header_magic[8] = {
452         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
453 };
454
455 /**
456  * Generate header only signature(s) from a header+payload file.
457  * @param sig           signature header
458  * @param file          header+payload file name
459  * @param sigTag        type of signature(s) to add
460  * @param passPhrase    private key pass phrase
461  * @return              0 on success, -1 on failure
462  */
463 static int makeHDRSignature(Header sig, const char * file, int_32 sigTag,
464                 /*@null@*/ const char * passPhrase)
465         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
466         /*@modifies sig, rpmGlobalMacroContext, fileSystem, internalState @*/
467 {
468     Header h = NULL;
469     FD_t fd = NULL;
470     byte * pkt;
471     int_32 pktlen;
472     const char * fn = NULL;
473     const char * sha1 = NULL;
474     int ret = -1;       /* assume failure. */
475
476     switch (sigTag) {
477     case RPMSIGTAG_SIZE:
478     case RPMSIGTAG_MD5:
479     case RPMSIGTAG_PGP5:        /* XXX legacy */
480     case RPMSIGTAG_PGP:
481     case RPMSIGTAG_GPG:
482         goto exit;
483         /*@notreached@*/ break;
484     case RPMSIGTAG_SHA1:
485         fd = Fopen(file, "r.fdio");
486         if (fd == NULL || Ferror(fd))
487             goto exit;
488         h = headerRead(fd, HEADER_MAGIC_YES);
489         if (h == NULL)
490             goto exit;
491         (void) Fclose(fd);      fd = NULL;
492
493         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
494             DIGEST_CTX ctx;
495             void * uh;
496             int_32 uht, uhc;
497         
498             if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
499             ||   uh == NULL)
500             {
501                 h = headerFree(h, NULL);
502                 goto exit;
503             }
504             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
505             (void) rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
506             (void) rpmDigestUpdate(ctx, uh, uhc);
507             (void) rpmDigestFinal(ctx, (void **)&sha1, NULL, 1);
508             uh = headerFreeData(uh, uht);
509         }
510         h = headerFree(h, NULL);
511
512         if (sha1 == NULL)
513             goto exit;
514         if (!headerAddEntry(sig, RPMSIGTAG_SHA1, RPM_STRING_TYPE, sha1, 1))
515             goto exit;
516         ret = 0;
517         break;
518     case RPMSIGTAG_DSA:
519         fd = Fopen(file, "r.fdio");
520         if (fd == NULL || Ferror(fd))
521             goto exit;
522         h = headerRead(fd, HEADER_MAGIC_YES);
523         if (h == NULL)
524             goto exit;
525         (void) Fclose(fd);      fd = NULL;
526         if (makeTempFile(NULL, &fn, &fd))
527             goto exit;
528         if (headerWrite(fd, h, HEADER_MAGIC_YES))
529             goto exit;
530         (void) Fclose(fd);      fd = NULL;
531         if (makeGPGSignature(fn, &pkt, &pktlen, passPhrase)
532         ||  !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
533             goto exit;
534         ret = 0;
535         break;
536     case RPMSIGTAG_RSA:
537         fd = Fopen(file, "r.fdio");
538         if (fd == NULL || Ferror(fd))
539             goto exit;
540         h = headerRead(fd, HEADER_MAGIC_YES);
541         if (h == NULL)
542             goto exit;
543         (void) Fclose(fd);      fd = NULL;
544         if (makeTempFile(NULL, &fn, &fd))
545             goto exit;
546         if (headerWrite(fd, h, HEADER_MAGIC_YES))
547             goto exit;
548         (void) Fclose(fd);      fd = NULL;
549         if (makePGPSignature(fn, &pkt, &pktlen, passPhrase)
550         ||  !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
551             goto exit;
552         ret = 0;
553         break;
554     }
555
556 exit:
557     if (fn) {
558         (void) unlink(fn);
559         fn = _free(fn);
560     }
561     sha1 = _free(sha1);
562     h = headerFree(h, NULL);
563     if (fd) (void) Fclose(fd);
564     return ret;
565 }
566
567 int rpmAddSignature(Header sig, const char * file, int_32 sigTag,
568                 const char * passPhrase)
569 {
570     struct stat st;
571     byte * pkt;
572     int_32 pktlen;
573     int ret = -1;       /* assume failure. */
574
575     switch (sigTag) {
576     case RPMSIGTAG_SIZE:
577         if (stat(file, &st) != 0)
578             break;
579         pktlen = st.st_size;
580         if (!headerAddEntry(sig, sigTag, RPM_INT32_TYPE, &pktlen, 1))
581             break;
582         ret = 0;
583         break;
584     case RPMSIGTAG_MD5:
585         pktlen = 16;
586         pkt = xcalloc(1, pktlen);
587         if (mdbinfile(file, pkt)
588         ||  !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
589             break;
590         ret = 0;
591         break;
592     case RPMSIGTAG_PGP5:        /* XXX legacy */
593     case RPMSIGTAG_PGP:
594         if (makePGPSignature(file, &pkt, &pktlen, passPhrase)
595         ||  !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
596             break;
597 #ifdef  NOTYET  /* XXX needs hdrmd5ctx, like hdrsha1ctx. */
598         /* XXX Piggyback a header-only RSA signature as well. */
599         ret = makeHDRSignature(sig, file, RPMSIGTAG_RSA, passPhrase);
600 #endif
601         ret = 0;
602         break;
603     case RPMSIGTAG_GPG:
604         if (makeGPGSignature(file, &pkt, &pktlen, passPhrase)
605         ||  !headerAddEntry(sig, sigTag, RPM_BIN_TYPE, pkt, pktlen))
606             break;
607         /* XXX Piggyback a header-only DSA signature as well. */
608         ret = makeHDRSignature(sig, file, RPMSIGTAG_DSA, passPhrase);
609         break;
610     case RPMSIGTAG_RSA:
611     case RPMSIGTAG_DSA:
612     case RPMSIGTAG_SHA1:
613         ret = makeHDRSignature(sig, file, sigTag, passPhrase);
614         break;
615     }
616
617     return ret;
618 }
619
620 static int checkPassPhrase(const char * passPhrase, const int sigTag)
621         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
622         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
623 {
624     int passPhrasePipe[2];
625     int pid, status;
626     int rc;
627     int xx;
628
629     passPhrasePipe[0] = passPhrasePipe[1] = 0;
630     xx = pipe(passPhrasePipe);
631     if (!(pid = fork())) {
632         const char * cmd;
633         char *const *av;
634         int fdno;
635
636         xx = close(STDIN_FILENO);
637         xx = close(STDOUT_FILENO);
638         xx = close(passPhrasePipe[1]);
639         if (! rpmIsVerbose())
640             xx = close(STDERR_FILENO);
641         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
642             xx = dup2(fdno, STDIN_FILENO);
643             xx = close(fdno);
644         }
645         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
646             xx = dup2(fdno, STDOUT_FILENO);
647             xx = close(fdno);
648         }
649         xx = dup2(passPhrasePipe[0], 3);
650
651         switch (sigTag) {
652         case RPMSIGTAG_DSA:
653         case RPMSIGTAG_GPG:
654         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
655
656             if (gpg_path && *gpg_path != '\0')
657                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
658
659             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
660             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
661             if (!rc)
662                 rc = execve(av[0], av+1, environ);
663
664             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
665                         strerror(errno));
666         }   /*@notreached@*/ break;
667         case RPMSIGTAG_RSA:
668         case RPMSIGTAG_PGP5:    /* XXX legacy */
669         case RPMSIGTAG_PGP:
670         {   const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
671             const char *path;
672             pgpVersion pgpVer;
673
674             (void) dosetenv("PGPPASSFD", "3", 1);
675             if (pgp_path && *pgp_path != '\0')
676                 xx = dosetenv("PGPPATH", pgp_path, 1);
677
678             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
679                 switch(pgpVer) {
680                 case PGP_2:
681                     cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL);
682                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
683                     if (!rc)
684                         rc = execve(av[0], av+1, environ);
685                     /*@innerbreak@*/ break;
686                 case PGP_5:     /* XXX legacy */
687                     cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL);
688                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
689                     if (!rc)
690                         rc = execve(av[0], av+1, environ);
691                     /*@innerbreak@*/ break;
692                 case PGP_UNKNOWN:
693                 case PGP_NOTDETECTED:
694                     /*@innerbreak@*/ break;
695                 }
696             }
697             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
698                         strerror(errno));
699             _exit(RPMERR_EXEC);
700         }   /*@notreached@*/ break;
701         default: /* This case should have been screened out long ago. */
702             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
703             _exit(RPMERR_SIGGEN);
704             /*@notreached@*/ break;
705         }
706     }
707
708     xx = close(passPhrasePipe[0]);
709     xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
710     xx = write(passPhrasePipe[1], "\n", 1);
711     xx = close(passPhrasePipe[1]);
712
713     (void) waitpid(pid, &status, 0);
714
715     return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
716 }
717
718 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
719 {
720     char *pass;
721     int aok;
722
723     switch (sigTag) {
724     case RPMSIGTAG_DSA:
725     case RPMSIGTAG_GPG:
726       { const char *name = rpmExpand("%{?_gpg_name}", NULL);
727         aok = (name && *name != '\0');
728         name = _free(name);
729       }
730         if (!aok) {
731             rpmError(RPMERR_SIGGEN,
732                 _("You must set \"%%_gpg_name\" in your macro file\n"));
733             return NULL;
734         }
735         break;
736     case RPMSIGTAG_RSA:
737     case RPMSIGTAG_PGP5:        /* XXX legacy */
738     case RPMSIGTAG_PGP:
739       { const char *name = rpmExpand("%{?_pgp_name}", NULL);
740         aok = (name && *name != '\0');
741         name = _free(name);
742       }
743         if (!aok) {
744             rpmError(RPMERR_SIGGEN,
745                 _("You must set \"%%_pgp_name\" in your macro file\n"));
746             return NULL;
747         }
748         break;
749     default:
750         /* Currently the calling function (rpm.c:main) is checking this and
751          * doing a better job.  This section should never be accessed.
752          */
753         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
754         return NULL;
755         /*@notreached@*/ break;
756     }
757
758     pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
759
760     if (checkPassPhrase(pass, sigTag))
761         return NULL;
762
763     return pass;
764 }
765
766 static /*@observer@*/ const char * rpmSigString(rpmVerifySignatureReturn res)
767         /*@*/
768 {
769     const char * str;
770     switch (res) {
771     case RPMSIG_OK:             str = "OK";             break;
772     case RPMSIG_BAD:            str = "BAD";            break;
773     case RPMSIG_NOKEY:          str = "NOKEY";          break;
774     case RPMSIG_NOTTRUSTED:     str = "NOTRUSTED";      break;
775     default:
776     case RPMSIG_UNKNOWN:        str = "UNKNOWN";        break;
777     }
778     return str;
779 }
780
781 static rpmVerifySignatureReturn
782 verifySizeSignature(const rpmTransactionSet ts, /*@out@*/ char * t)
783         /*@modifies *t @*/
784 {
785     rpmVerifySignatureReturn res;
786     int_32 size = 0x7fffffff;
787
788     *t = '\0';
789     t = stpcpy(t, _("Header+Payload size: "));
790
791     if (ts->sig == NULL || ts->dig == NULL || ts->dig->nbytes == 0) {
792         res = RPMSIG_NOKEY;             /* XXX RPMSIG_ARGS */
793         res = RPMSIG_NOKEY;
794         t = stpcpy(t, rpmSigString(res));
795         goto exit;
796     }
797
798     memcpy(&size, ts->sig, sizeof(size));
799
800     if (size != ts->dig->nbytes) {
801         res = RPMSIG_BAD;
802         t = stpcpy(t, rpmSigString(res));
803         sprintf(t, " Expected(%d) != (%d)\n", size, ts->dig->nbytes);
804     } else {
805         res = RPMSIG_OK;
806         t = stpcpy(t, rpmSigString(res));
807         sprintf(t, " (%d)", ts->dig->nbytes);
808     }
809
810 exit:
811     t = stpcpy(t, "\n");
812     return res;
813 }
814
815 static rpmVerifySignatureReturn
816 verifyMD5Signature(const rpmTransactionSet ts, /*@out@*/ char * t,
817                 /*@null@*/ DIGEST_CTX md5ctx)
818         /*@modifies *t @*/
819 {
820     rpmVerifySignatureReturn res;
821     byte * md5sum = NULL;
822     size_t md5len = 0;
823
824     *t = '\0';
825     t = stpcpy(t, _("MD5 digest: "));
826
827     if (md5ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
828         res = RPMSIG_NOKEY;             /* XXX RPMSIG_ARGS */
829         t = stpcpy(t, rpmSigString(res));
830         goto exit;
831     }
832
833     (void) rpmDigestFinal(rpmDigestDup(md5ctx),
834                 (void **)&md5sum, &md5len, 0);
835
836     if (md5len != ts->siglen || memcmp(md5sum, ts->sig, md5len)) {
837         res = RPMSIG_BAD;
838         t = stpcpy(t, rpmSigString(res));
839         t = stpcpy(t, " Expected(");
840         (void) pgpHexCvt(t, ts->sig, ts->siglen);
841         t += strlen(t);
842         t = stpcpy(t, ") != (");
843     } else {
844         res = RPMSIG_OK;
845         t = stpcpy(t, rpmSigString(res));
846         t = stpcpy(t, " (");
847     }
848     (void) pgpHexCvt(t, md5sum, md5len);
849     t += strlen(t);
850     t = stpcpy(t, ")");
851
852 exit:
853     md5sum = _free(md5sum);
854     t = stpcpy(t, "\n");
855     return res;
856 }
857
858 /**
859  * Verify header immutable region SHA1 digest.
860  * @param ts            transaction set
861  * @retval t            verbose success/failure text
862  * @param sha1ctx
863  * @return              RPMSIG_OK on success
864  */
865 static rpmVerifySignatureReturn
866 verifySHA1Signature(const rpmTransactionSet ts, /*@out@*/ char * t,
867                 /*@null@*/ DIGEST_CTX sha1ctx)
868         /*@modifies *t @*/
869 {
870     rpmVerifySignatureReturn res;
871     const char * sha1 = NULL;
872
873     *t = '\0';
874     t = stpcpy(t, _("Header SHA1 digest: "));
875
876     if (sha1ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
877         res = RPMSIG_NOKEY;             /* XXX RPMSIG_ARGS */
878         t = stpcpy(t, rpmSigString(res));
879         goto exit;
880     }
881
882     (void) rpmDigestFinal(rpmDigestDup(sha1ctx),
883                 (void **)&sha1, NULL, 1);
884
885     if (sha1 == NULL || strlen(sha1) != strlen(ts->sig)) {
886         res = RPMSIG_BAD;
887         t = stpcpy(t, rpmSigString(res));
888         t = stpcpy(t, " Expected(");
889         t = stpcpy(t, ts->sig);
890         t = stpcpy(t, ") != (");
891     } else {
892         res = RPMSIG_OK;
893         t = stpcpy(t, rpmSigString(res));
894         t = stpcpy(t, " (");
895     }
896     if (sha1)
897         t = stpcpy(t, sha1);
898     t = stpcpy(t, ")");
899
900 exit:
901     sha1 = _free(sha1);
902     t = stpcpy(t, "\n");
903     return res;
904 }
905
906 /**
907  * Retrieve pubkey from rpm database.
908  * @param ts            rpm transaction
909  * @return              RPMSIG_OK on success, RPMSIG_NOKEY if not found
910  */
911 static rpmVerifySignatureReturn
912 rpmtsFindPubkey(rpmTransactionSet ts)
913         /*@globals fileSystem, internalState @*/
914         /*@modifies ts, fileSystem, internalState */
915 {
916     struct pgpDigParams_s * sigp = NULL;
917     rpmVerifySignatureReturn res;
918     /*@unchecked@*/ /*@only@*/ static const byte * pkpkt = NULL;
919     /*@unchecked@*/ static size_t pkpktlen = 0;
920     /*@unchecked@*/ static byte pksignid[8];
921     int xx;
922
923     if (ts->sig == NULL || ts->dig == NULL) {
924         res = RPMSIG_NOKEY;
925         goto exit;
926     }
927     sigp = &ts->dig->signature;
928
929     if (pkpkt == NULL || memcmp(sigp->signid, pksignid, sizeof(pksignid))) {
930         int ix = -1;
931         rpmdbMatchIterator mi;
932         Header h;
933
934         pkpkt = _free(pkpkt);
935         pkpktlen = 0;
936         memset(pksignid, 0, sizeof(pksignid));
937
938         /* Make sure the database is open. */
939         (void) rpmtsOpenDB(ts, ts->dbmode);
940
941         /* Retrieve the pubkey that matches the signature. */
942         mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
943         while ((h = rpmdbNextIterator(mi)) != NULL) {
944             const char ** pubkeys;
945             int_32 pt, pc;
946
947             if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc))
948                 continue;
949             ix = rpmdbGetIteratorFileNum(mi);
950             if (ix >= pc
951             || b64decode(pubkeys[ix], (void **) &pkpkt, &pkpktlen))
952                 ix = -1;
953             pubkeys = headerFreeData(pubkeys, pt);
954             break;
955         }
956         mi = rpmdbFreeIterator(mi);
957
958         /* Was a matching pubkey found? */
959         if (ix < 0 || pkpkt == NULL) {
960             res = RPMSIG_NOKEY;
961             goto exit;
962         }
963
964         /*
965          * Can the pubkey packets be parsed?
966          * Do the parameters match the signature?
967          */
968         if (pgpPrtPkts(pkpkt, pkpktlen, NULL, 0)
969          && ts->dig->signature.pubkey_algo == ts->dig->pubkey.pubkey_algo
970 #ifdef  NOTYET
971          && ts->dig->signature.hash_algo == ts->dig->pubkey.hash_algo
972 #endif
973          && !memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8))
974         {
975             pkpkt = _free(pkpkt);
976             pkpktlen = 0;
977             res = RPMSIG_NOKEY;
978             goto exit;
979         }
980
981         /* XXX Verify the pubkey signature. */
982
983         /* Packet looks good, save the signer id. */
984         memcpy(pksignid, sigp->signid, sizeof(pksignid));
985
986         rpmMessage(RPMMESS_DEBUG, "========== %s pubkey id %s\n",
987                 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
988                 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
989                 pgpHexStr(sigp->signid, sizeof(sigp->signid)));
990
991     }
992
993 #ifdef  NOTNOW
994     {
995         if (pkpkt == NULL) {
996             const char * pkfn = rpmExpand("%{_gpg_pubkey}", NULL);
997             if (pgpReadPkts(pkfn, &pkpkt, &pkpktlen) != PGPARMOR_PUBKEY) {
998                 pkfn = _free(pkfn);
999                 res = RPMSIG_NOKEY;
1000                 goto exit;
1001             }
1002             pkfn = _free(pkfn);
1003         }
1004     }
1005 #endif
1006
1007     /* Retrieve parameters from pubkey packet(s). */
1008     xx = pgpPrtPkts(pkpkt, pkpktlen, ts->dig, 0);
1009
1010     /* Do the parameters match the signature? */
1011     if (ts->dig->signature.pubkey_algo == ts->dig->pubkey.pubkey_algo
1012 #ifdef  NOTYET
1013      && ts->dig->signature.hash_algo == ts->dig->pubkey.hash_algo
1014 #endif
1015      && !memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8))
1016         res = RPMSIG_OK;
1017     else
1018         res = RPMSIG_NOKEY;
1019
1020     /* XXX Verify the signature signature. */
1021
1022 exit:
1023     return res;
1024 }
1025
1026 /**
1027  * Convert hex to binary nibble.
1028  * @param c            hex character
1029  * @return             binary nibble
1030  */
1031 static inline unsigned char nibble(char c)
1032         /*@*/
1033 {
1034     if (c >= '0' && c <= '9')
1035         return (c - '0');
1036     if (c >= 'A' && c <= 'F')
1037         return (c - 'A') + 10;
1038     if (c >= 'a' && c <= 'f')
1039         return (c - 'a') + 10;
1040     return 0;
1041 }
1042
1043 /**
1044  * Verify PGP (aka RSA/MD5) signature.
1045  * @param ts            transaction set
1046  * @retval t            verbose success/failure text
1047  * @param md5ctx
1048  * @return              RPMSIG_OK on success
1049  */
1050 static rpmVerifySignatureReturn
1051 verifyPGPSignature(rpmTransactionSet ts, /*@out@*/ char * t,
1052                 /*@null@*/ DIGEST_CTX md5ctx)
1053         /*@globals fileSystem, internalState @*/
1054         /*@modifies ts, *t, fileSystem, internalState */
1055 {
1056     struct pgpDigParams_s * sigp = NULL;
1057     rpmVerifySignatureReturn res;
1058     int xx;
1059
1060     *t = '\0';
1061     t = stpcpy(t, _("V3 RSA/MD5 signature: "));
1062
1063     if (md5ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
1064         res = RPMSIG_NOKEY;             /* XXX RPMSIG_ARGS */
1065         goto exit;
1066     }
1067     sigp = &ts->dig->signature;
1068
1069     /* XXX sanity check on ts->sigtag and signature agreement. */
1070     if (!(ts->sigtag == RPMSIGTAG_PGP
1071         && sigp->pubkey_algo == PGPPUBKEYALGO_RSA
1072         && sigp->hash_algo == PGPHASHALGO_MD5))
1073     {
1074         res = RPMSIG_NOKEY;
1075         goto exit;
1076     }
1077
1078     {   DIGEST_CTX ctx = rpmDigestDup(md5ctx);
1079         byte signhash16[2];
1080         const char * s;
1081
1082         if (sigp->hash != NULL)
1083             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
1084
1085 #ifdef  NOTYET  /* XXX not for binary/text document signatures. */
1086         if (sigp->sigtype == 4) {
1087             int nb = ts->dig->nbytes + sigp->hashlen;
1088             byte trailer[6];
1089             nb = htonl(nb);
1090             trailer[0] = 0x4;
1091             trailer[1] = 0xff;
1092             memcpy(trailer+2, &nb, sizeof(nb));
1093             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
1094         }
1095 #endif
1096
1097         xx = rpmDigestFinal(ctx, (void **)&ts->dig->md5, &ts->dig->md5len, 1);
1098
1099         /* Compare leading 16 bits of digest for quick check. */
1100         s = ts->dig->md5;
1101         signhash16[0] = (nibble(s[0]) << 4) | nibble(s[1]);
1102         signhash16[1] = (nibble(s[2]) << 4) | nibble(s[3]);
1103         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
1104             res = RPMSIG_BAD;
1105             goto exit;
1106         }
1107
1108     }
1109
1110     {   const char * prefix = "3020300c06082a864886f70d020505000410";
1111         unsigned int nbits = 1024;
1112         unsigned int nb = (nbits + 7) >> 3;
1113         const char * hexstr;
1114         char * tt;
1115
1116         hexstr = tt = xmalloc(2 * nb + 1);
1117         memset(tt, 'f', (2 * nb));
1118         tt[0] = '0'; tt[1] = '0';
1119         tt[2] = '0'; tt[3] = '1';
1120         tt += (2 * nb) - strlen(prefix) - strlen(ts->dig->md5) - 2;
1121         *tt++ = '0'; *tt++ = '0';
1122         tt = stpcpy(tt, prefix);
1123         tt = stpcpy(tt, ts->dig->md5);
1124
1125         mp32nzero(&ts->dig->rsahm);     mp32nsethex(&ts->dig->rsahm, hexstr);
1126
1127         hexstr = _free(hexstr);
1128
1129     }
1130
1131     /* Retrieve the matching public key. */
1132     res = rpmtsFindPubkey(ts);
1133     if (res != RPMSIG_OK)
1134         goto exit;
1135
1136     if (rsavrfy(&ts->dig->rsa_pk, &ts->dig->rsahm, &ts->dig->c))
1137         res = RPMSIG_OK;
1138     else
1139         res = RPMSIG_BAD;
1140
1141 exit:
1142     t = stpcpy(t, rpmSigString(res));
1143     if (sigp != NULL) {
1144         t = stpcpy(t, ", key ID ");
1145         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
1146         t += strlen(t);
1147     }
1148     t = stpcpy(t, "\n");
1149     return res;
1150 }
1151
1152 /**
1153  * Verify GPG (aka DSA) signature.
1154  * @param ts            transaction set
1155  * @retval t            verbose success/failure text
1156  * @param sha1ctx
1157  * @return              RPMSIG_OK on success
1158  */
1159 static rpmVerifySignatureReturn
1160 verifyGPGSignature(rpmTransactionSet ts, /*@out@*/ char * t,
1161                 /*@null@*/ DIGEST_CTX sha1ctx)
1162         /*@globals fileSystem, internalState @*/
1163         /*@modifies ts, *t, fileSystem, internalState */
1164 {
1165     struct pgpDigParams_s * sigp = NULL;
1166     rpmVerifySignatureReturn res;
1167     int xx;
1168
1169     *t = '\0';
1170     if (ts->dig != NULL && ts->dig->hdrsha1ctx == sha1ctx)
1171         t = stpcpy(t, _("Header "));
1172     t = stpcpy(t, _("V3 DSA signature: "));
1173
1174     if (sha1ctx == NULL || ts->sig == NULL || ts->dig == NULL) {
1175         res = RPMSIG_NOKEY;             /* XXX RPMSIG_ARGS */
1176         goto exit;
1177     }
1178     sigp = &ts->dig->signature;
1179
1180     /* XXX sanity check on ts->sigtag and signature agreement. */
1181     if (!((ts->sigtag == RPMSIGTAG_GPG || ts->sigtag == RPMSIGTAG_DSA)
1182         && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
1183         && sigp->hash_algo == PGPHASHALGO_SHA1))
1184     {
1185         res = RPMSIG_NOKEY;
1186         goto exit;
1187     }
1188
1189     {   DIGEST_CTX ctx = rpmDigestDup(sha1ctx);
1190         byte signhash16[2];
1191
1192         if (sigp->hash != NULL)
1193             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
1194
1195 #ifdef  NOTYET  /* XXX not for binary/text document signatures. */
1196         if (sigp->sigtype == 4) {
1197             int nb = ts->dig->nbytes + sigp->hashlen;
1198             byte trailer[6];
1199             nb = htonl(nb);
1200             trailer[0] = 0x4;
1201             trailer[1] = 0xff;
1202             memcpy(trailer+2, &nb, sizeof(nb));
1203             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
1204         }
1205 #endif
1206         xx = rpmDigestFinal(ctx, (void **)&ts->dig->sha1, &ts->dig->sha1len, 1);
1207
1208         mp32nzero(&ts->dig->hm);        mp32nsethex(&ts->dig->hm, ts->dig->sha1);
1209
1210         /* Compare leading 16 bits of digest for quick check. */
1211         signhash16[0] = (*ts->dig->hm.data >> 24) & 0xff;
1212         signhash16[1] = (*ts->dig->hm.data >> 16) & 0xff;
1213         if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) {
1214             res = RPMSIG_BAD;
1215             goto exit;
1216         }
1217     }
1218
1219     /* Retrieve the matching public key. */
1220     res = rpmtsFindPubkey(ts);
1221     if (res != RPMSIG_OK)
1222         goto exit;
1223
1224     if (dsavrfy(&ts->dig->p, &ts->dig->q, &ts->dig->g,
1225                 &ts->dig->hm, &ts->dig->y, &ts->dig->r, &ts->dig->s))
1226         res = RPMSIG_OK;
1227     else
1228         res = RPMSIG_BAD;
1229
1230 exit:
1231     t = stpcpy(t, rpmSigString(res));
1232     if (sigp != NULL) {
1233         t = stpcpy(t, ", key ID ");
1234         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
1235         t += strlen(t);
1236     }
1237     t = stpcpy(t, "\n");
1238     return res;
1239 }
1240
1241 rpmVerifySignatureReturn
1242 rpmVerifySignature(const rpmTransactionSet ts, char * result)
1243 {
1244     rpmVerifySignatureReturn res;
1245
1246     if (ts->sig == NULL || ts->siglen <= 0 || ts->dig == NULL) {
1247         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
1248         return RPMSIG_UNKNOWN;
1249     }
1250
1251     switch (ts->sigtag) {
1252     case RPMSIGTAG_SIZE:
1253         res = verifySizeSignature(ts, result);
1254         break;
1255     case RPMSIGTAG_MD5:
1256         res = verifyMD5Signature(ts, result, ts->dig->md5ctx);
1257         break;
1258     case RPMSIGTAG_SHA1:
1259         res = verifySHA1Signature(ts, result, ts->dig->hdrsha1ctx);
1260         break;
1261     case RPMSIGTAG_RSA:
1262     case RPMSIGTAG_PGP5:        /* XXX legacy */
1263     case RPMSIGTAG_PGP:
1264         res = verifyPGPSignature(ts, result, ts->dig->md5ctx);
1265         break;
1266     case RPMSIGTAG_DSA:
1267         res = verifyGPGSignature(ts, result, ts->dig->hdrsha1ctx);
1268         break;
1269     case RPMSIGTAG_GPG:
1270         res = verifyGPGSignature(ts, result, ts->dig->sha1ctx);
1271         break;
1272     case RPMSIGTAG_LEMD5_1:
1273     case RPMSIGTAG_LEMD5_2:
1274         sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
1275         res = RPMSIG_UNKNOWN;
1276         break;
1277     default:
1278         sprintf(result, _("Signature: UNKNOWN (%d)\n"), ts->sigtag);
1279         res = RPMSIG_UNKNOWN;
1280         break;
1281     }
1282     return res;
1283 }