Start ripping gpg/pgp on signature verify paths.
[platform/upstream/rpm.git] / lib / signature.c
1 /*@-mods@*/
2 /** \ingroup signature
3  * \file lib/signature.c
4  */
5
6 #include "system.h"
7
8 #include "rpmio_internal.h"
9 #include <rpmlib.h>
10 #include <rpmmacro.h>   /* XXX for rpmGetPath() */
11
12 #include "misc.h"       /* XXX for dosetenv() and makeTempFile() */
13 #include "rpmlead.h"
14 #include "signature.h"
15 #include "debug.h"
16
17 /*@access Header@*/             /* XXX compared with NULL */
18 /*@access FD_t@*/               /* XXX compared with NULL */
19
20 int rpmLookupSignatureType(int action)
21 {
22     static int disabled = 0;
23     int rc = 0;
24
25     switch (action) {
26     case RPMLOOKUPSIG_DISABLE:
27         disabled = -2;
28         break;
29     case RPMLOOKUPSIG_ENABLE:
30         disabled = 0;
31         /*@fallthrough@*/
32     case RPMLOOKUPSIG_QUERY:
33         if (disabled)
34             break;      /* Disabled */
35       { const char *name = rpmExpand("%{_signature}", NULL);
36         if (!(name && *name != '%'))
37             rc = 0;
38         else if (!xstrcasecmp(name, "none"))
39             rc = 0;
40         else if (!xstrcasecmp(name, "pgp"))
41             rc = RPMSIGTAG_PGP;
42         else if (!xstrcasecmp(name, "pgp5"))    /* XXX legacy */
43             rc = RPMSIGTAG_PGP;
44         else if (!xstrcasecmp(name, "gpg"))
45             rc = RPMSIGTAG_GPG;
46         else
47             rc = -1;    /* Invalid %_signature spec in macro file */
48         name = _free(name);
49       } break;
50     }
51     return rc;
52 }
53
54 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
55 /* executable of the requested version, or NULL when none found. */
56
57 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
58 {
59     /* Actually this should support having more then one pgp version. */
60     /* At the moment only one version is possible since we only       */
61     /* have one %_pgpbin and one %_pgp_path.                          */
62
63     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
64     const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL);
65
66     if (saved_pgp_version == PGP_UNKNOWN) {
67         char *pgpvbin;
68         struct stat st;
69
70         if (!(pgpbin && pgpbin[0] != '%')) {
71           pgpbin = _free(pgpbin);
72           saved_pgp_version = -1;
73           return NULL;
74         }
75         pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
76         (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
77
78         if (stat(pgpvbin, &st) == 0)
79           saved_pgp_version = PGP_5;
80         else if (stat(pgpbin, &st) == 0)
81           saved_pgp_version = PGP_2;
82         else
83           saved_pgp_version = PGP_NOTDETECTED;
84     }
85
86     if (pgpVer && pgpbin)
87         *pgpVer = saved_pgp_version;
88     return pgpbin;
89 }
90
91 /**
92  * Check package size.
93  * @todo rpmio: use fdSize rather than fstat(2) to get file size.
94  * @param fd                    package file handle
95  * @param siglen                signature header size
96  * @param pad                   signature padding
97  * @param datalen               length of header+payload
98  * @return                      rpmRC return code
99  */
100 static inline rpmRC checkSize(FD_t fd, int siglen, int pad, int datalen)
101         /*@globals fileSystem @*/
102         /*@modifies fileSystem @*/
103 {
104     struct stat st;
105     rpmRC rc;
106
107     if (fstat(Fileno(fd), &st))
108         return RPMRC_FAIL;
109
110     if (!S_ISREG(st.st_mode)) {
111         rpmMessage(RPMMESS_DEBUG,
112             _("file is not regular -- skipping size check\n"));
113         return RPMRC_OK;
114     }
115
116     /*@-sizeoftype@*/
117     rc = (((sizeof(struct rpmlead) + siglen + pad + datalen) - st.st_size)
118         ? RPMRC_BADSIZE : RPMRC_OK);
119
120     rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_WARNING),
121         _("Expected size: %12d = lead(%d)+sigs(%d)+pad(%d)+data(%d)\n"),
122                 (int)sizeof(struct rpmlead)+siglen+pad+datalen,
123                 (int)sizeof(struct rpmlead), siglen, pad, datalen);
124     /*@=sizeoftype@*/
125     rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_WARNING),
126         _("  Actual size: %12d\n"), (int)st.st_size);
127
128     return rc;
129 }
130
131 rpmRC rpmReadSignature(FD_t fd, Header * headerp, sigType sig_type)
132 {
133     byte buf[2048];
134     int sigSize, pad;
135     int_32 type, count;
136     int_32 *archSize;
137     Header h = NULL;
138     rpmRC rc = RPMRC_FAIL;              /* assume failure */
139
140     if (headerp)
141         *headerp = NULL;
142
143     buf[0] = 0;
144     switch (sig_type) {
145     case RPMSIGTYPE_NONE:
146         rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
147         rc = RPMRC_OK;
148         break;
149     case RPMSIGTYPE_PGP262_1024:
150         rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
151         /* These are always 256 bytes */
152         /*@-type@*/ /* FIX: eliminate timedRead @*/
153         if (timedRead(fd, buf, 256) != 256)
154             break;
155         /*@=type@*/
156         h = headerNew();
157         (void) headerAddEntry(h, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
158         rc = RPMRC_OK;
159         break;
160     case RPMSIGTYPE_MD5:
161     case RPMSIGTYPE_MD5_PGP:
162         rpmError(RPMERR_BADSIGTYPE,
163               _("Old (internal-only) signature!  How did you get that!?\n"));
164         break;
165     case RPMSIGTYPE_HEADERSIG:
166     case RPMSIGTYPE_DISABLE:
167         /* This is a new style signature */
168         h = headerRead(fd, HEADER_MAGIC_YES);
169         if (h == NULL)
170             break;
171
172         rc = RPMRC_OK;
173         sigSize = headerSizeof(h, HEADER_MAGIC_YES);
174
175         /* XXX Legacy headers have a HEADER_IMAGE tag added. */
176         if (headerIsEntry(h, RPMTAG_HEADERIMAGE))
177             sigSize -= (16 + 16);
178
179         pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
180         if (sig_type == RPMSIGTYPE_HEADERSIG) {
181             if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type,
182                                 (void **)&archSize, &count))
183                 break;
184             rc = checkSize(fd, sigSize, pad, *archSize);
185         }
186         /*@-type@*/ /* FIX: eliminate timedRead @*/
187         if (pad && timedRead(fd, buf, pad) != pad)
188             rc = RPMRC_SHORTREAD;
189         /*@=type@*/
190         break;
191     default:
192         break;
193     }
194
195     if (headerp && rc == 0)
196         *headerp = h;
197     else
198         h = headerFree(h);
199
200     return rc;
201 }
202
203 int rpmWriteSignature(FD_t fd, Header h)
204 {
205     static byte buf[8] = "\000\000\000\000\000\000\000\000";
206     int sigSize, pad;
207     int rc;
208
209     rc = headerWrite(fd, h, HEADER_MAGIC_YES);
210     if (rc)
211         return rc;
212
213     sigSize = headerSizeof(h, HEADER_MAGIC_YES);
214     pad = (8 - (sigSize % 8)) % 8;
215     if (pad) {
216         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
217             rc = 1;
218     }
219     rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
220     return rc;
221 }
222
223 Header rpmNewSignature(void)
224 {
225     Header h = headerNew();
226     return h;
227 }
228
229 Header rpmFreeSignature(Header h)
230 {
231     return headerFree(h);
232 }
233
234 static int makePGPSignature(const char * file, /*@out@*/ void ** sig,
235                 /*@out@*/ int_32 * size, /*@null@*/ const char * passPhrase)
236         /*@globals rpmGlobalMacroContext,
237                 fileSystem @*/
238         /*@modifies *sig, *size, fileSystem @*/
239 {
240     char * sigfile = alloca(1024);
241     int pid, status;
242     int inpipe[2];
243     struct stat st;
244
245     (void) stpcpy( stpcpy(sigfile, file), ".sig");
246
247     inpipe[0] = inpipe[1] = 0;
248     (void) pipe(inpipe);
249
250     if (!(pid = fork())) {
251         const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
252         const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
253         const char *path;
254         pgpVersion pgpVer;
255
256         (void) close(STDIN_FILENO);
257         (void) dup2(inpipe[0], 3);
258         (void) close(inpipe[1]);
259
260         (void) dosetenv("PGPPASSFD", "3", 1);
261         if (pgp_path && *pgp_path != '%')
262             (void) dosetenv("PGPPATH", pgp_path, 1);
263
264         /* dosetenv("PGPPASS", passPhrase, 1); */
265
266         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
267             switch(pgpVer) {
268             case PGP_2:
269                 (void) execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off",
270                     name, "-sb", file, sigfile, NULL);
271                 break;
272             case PGP_5:
273                 (void) execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off",
274                     name, "-b", file, "-o", sigfile, NULL);
275                 break;
276             case PGP_UNKNOWN:
277             case PGP_NOTDETECTED:
278                 break;
279             }
280         }
281         rpmError(RPMERR_EXEC, _("Couldn't exec pgp (%s)\n"),
282                         (path ? path : NULL));
283         _exit(RPMERR_EXEC);
284     }
285
286     (void) close(inpipe[0]);
287     if (passPhrase)
288         (void) write(inpipe[1], passPhrase, strlen(passPhrase));
289     (void) write(inpipe[1], "\n", 1);
290     (void) close(inpipe[1]);
291
292     (void)waitpid(pid, &status, 0);
293     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
294         rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
295         return 1;
296     }
297
298     if (stat(sigfile, &st)) {
299         /* PGP failed to write signature */
300         if (sigfile) (void) unlink(sigfile);  /* Just in case */
301         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
302         return 1;
303     }
304
305     *size = st.st_size;
306     rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *size);
307     *sig = xmalloc(*size);
308
309     {   FD_t fd;
310         int rc = 0;
311         fd = Fopen(sigfile, "r.fdio");
312         if (fd != NULL && !Ferror(fd)) {
313             /*@-type@*/ /* FIX: eliminate timedRead @*/
314             rc = timedRead(fd, *sig, *size);
315             /*@=type@*/
316             if (sigfile) (void) unlink(sigfile);
317             (void) Fclose(fd);
318         }
319         if (rc != *size) {
320             *sig = _free(*sig);
321             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
322             return 1;
323         }
324     }
325
326     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *size);
327
328     return 0;
329 }
330
331 /* This is an adaptation of the makePGPSignature function to use GPG instead
332  * of PGP to create signatures.  I think I've made all the changes necessary,
333  * but this could be a good place to start looking if errors in GPG signature
334  * creation crop up.
335  */
336 static int makeGPGSignature(const char * file, /*@out@*/ void ** sig,
337                 /*@out@*/ int_32 * size, /*@null@*/ const char * passPhrase)
338         /*@globals rpmGlobalMacroContext,
339                 fileSystem @*/
340         /*@modifies *sig, *size, fileSystem @*/
341 {
342     char * sigfile = alloca(1024);
343     int pid, status;
344     int inpipe[2];
345     FILE * fpipe;
346     struct stat st;
347
348     (void) stpcpy( stpcpy(sigfile, file), ".sig");
349
350     inpipe[0] = inpipe[1] = 0;
351     (void) pipe(inpipe);
352
353     if (!(pid = fork())) {
354         const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
355         const char *name = rpmExpand("%{_gpg_name}", NULL);
356
357         (void) close(STDIN_FILENO);
358         (void) dup2(inpipe[0], 3);
359         (void) close(inpipe[1]);
360
361         if (gpg_path && *gpg_path != '%')
362             (void) dosetenv("GNUPGHOME", gpg_path, 1);
363         (void) execlp("gpg", "gpg",
364                "--batch", "--no-verbose", "--no-armor", "--passphrase-fd", "3",
365                "-u", name, "-sbo", sigfile, file,
366                NULL);
367         rpmError(RPMERR_EXEC, _("Couldn't exec gpg\n"));
368         _exit(RPMERR_EXEC);
369     }
370
371     fpipe = fdopen(inpipe[1], "w");
372     (void) close(inpipe[0]);
373     if (fpipe) {
374         fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
375         (void) fclose(fpipe);
376     }
377
378     (void)waitpid(pid, &status, 0);
379     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
380         rpmError(RPMERR_SIGGEN, _("gpg failed\n"));
381         return 1;
382     }
383
384     if (stat(sigfile, &st)) {
385         /* GPG failed to write signature */
386         if (sigfile) (void) unlink(sigfile);  /* Just in case */
387         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
388         return 1;
389     }
390
391     *size = st.st_size;
392     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *size);
393     *sig = xmalloc(*size);
394
395     {   FD_t fd;
396         int rc = 0;
397         fd = Fopen(sigfile, "r.fdio");
398         if (fd != NULL && !Ferror(fd)) {
399             /*@-type@*/ /* FIX: eliminate timedRead @*/
400             rc = timedRead(fd, *sig, *size);
401             /*@=type@*/
402             if (sigfile) (void) unlink(sigfile);
403             (void) Fclose(fd);
404         }
405         if (rc != *size) {
406             *sig = _free(*sig);
407             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
408             return 1;
409         }
410     }
411
412     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *size);
413
414     return 0;
415 }
416
417 int rpmAddSignature(Header h, const char * file, int_32 sigTag,
418                 const char *passPhrase)
419 {
420     struct stat st;
421     int_32 size;
422     byte buf[16];
423     void *sig;
424     int ret = -1;
425
426     switch (sigTag) {
427     case RPMSIGTAG_SIZE:
428         (void) stat(file, &st);
429         size = st.st_size;
430         ret = 0;
431         (void) headerAddEntry(h, RPMSIGTAG_SIZE, RPM_INT32_TYPE, &size, 1);
432         break;
433     case RPMSIGTAG_MD5:
434         ret = mdbinfile(file, buf);
435         if (ret == 0)
436             (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, buf, 16);
437         break;
438     case RPMSIGTAG_PGP5:        /* XXX legacy */
439     case RPMSIGTAG_PGP:
440         rpmMessage(RPMMESS_VERBOSE, _("Generating signature using PGP.\n"));
441         ret = makePGPSignature(file, &sig, &size, passPhrase);
442         if (ret == 0)
443             (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, sig, size);
444         break;
445     case RPMSIGTAG_GPG:
446         rpmMessage(RPMMESS_VERBOSE, _("Generating signature using GPG.\n"));
447         ret = makeGPGSignature(file, &sig, &size, passPhrase);
448         if (ret == 0)
449             (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, sig, size);
450         break;
451     }
452
453     return ret;
454 }
455
456 /*@-globuse@*/
457 static rpmVerifySignatureReturn
458 verifySizeSignature(const char * datafile, int_32 size, /*@out@*/ char * result)
459         /*@globals fileSystem @*/
460         /*@modifies *result, fileSystem @*/
461 {
462     struct stat st;
463
464     (void) stat(datafile, &st);
465     if (size != st.st_size) {
466         sprintf(result, "Header+Archive size mismatch.\n"
467                 "Expected %d, saw %d.\n",
468                 size, (int)st.st_size);
469         return RPMSIG_BAD;
470     }
471
472     sprintf(result, "Header+Archive size OK: %d bytes\n", size);
473     return RPMSIG_OK;
474 }
475 /*@=globuse@*/
476
477 /*@-globuse@*/
478 static rpmVerifySignatureReturn
479 verifyMD5Signature(const char * datafile, const byte * sig, int siglen,
480                 const rpmDigest dig, /*@out@*/ char * result, md5func fn)
481         /*@globals fileSystem @*/
482         /*@modifies *result, fileSystem @*/
483 {
484     char * t = result;
485     byte * md5sum = NULL;
486     size_t md5len = 0;
487     int res = RPMSIG_BAD;
488
489     /*@-branchstate@*/
490     if (dig != NULL) {
491 /*@-type@*/
492         DIGEST_CTX ctx = rpmDigestDup(dig->md5ctx);
493         (void) rpmDigestFinal(ctx, (void **)&md5sum, &md5len, 0);
494 /*@=type@*/
495     } else {
496         int xx;
497         md5len = 16;
498         md5sum = xcalloc(1, md5len);
499         xx = fn(datafile, md5sum);
500     }
501     /*@=branchstate@*/
502
503     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
504         res = RPMSIG_BAD;
505         t = stpcpy(t, "  Expected: ");
506         (void) pgpHexCvt(t, sig, siglen);
507         t += strlen(t);
508         t = stpcpy(t, "    Actual: ");
509     } else {
510         res = RPMSIG_OK;
511         t = stpcpy(t, "MD5 sum OK: ");
512     }
513     (void) pgpHexCvt(t, md5sum, md5len);
514
515     md5sum = _free(md5sum);
516
517     return res;
518 }
519 /*@=globuse@*/
520
521 static rpmVerifySignatureReturn
522 verifyPGPSignature(/*@unused@*/ const char * datafile,
523                 /*@unused@*/ const byte * sig,
524                 /*@unused@*/ int siglen,
525                 const rpmDigest dig, /*@out@*/ char * result)
526         /*@modifies *result */
527 {
528     int res, resbc;
529
530     *result = '\0';
531
532     /*@-type@*/
533     if (rsavrfy(&dig->rsa_pk, &dig->rsahm, &dig->c)) {
534         res = resbc = RPMSIG_OK;
535     } else {
536         res = resbc = RPMSIG_BAD;
537     }
538     /*@=type@*/
539
540 #ifdef DYING
541   { int pid, status, outpipe[2];
542 /*@only@*/ /*@null@*/ const char * sigfile = NULL;
543     byte buf[BUFSIZ];
544     FILE *file;
545     const char *path;
546     pgpVersion pgpVer;
547
548     /* What version do we have? */
549     if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) {
550         errno = ENOENT;
551         rpmError(RPMERR_EXEC,
552                  _("Could not run pgp.  Use --nopgp to skip PGP checks.\n"));
553         _exit(RPMERR_EXEC);
554     }
555
556     /*
557      * Sad but true: pgp-5.0 returns exit value of 0 on bad signature.
558      * Instead we have to use the text output to detect a bad signature.
559      */
560     if (pgpVer == PGP_5)
561         res = RPMSIG_BAD;
562
563     /* Write out the signature */
564 #ifdef  DYING
565   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
566     sigfile = tempnam(tmppath, "rpmsig");
567     tmppath = _free(tmppath);
568   }
569     sfd = Fopen(sigfile, "w.fdio");
570     if (sfd != NULL && !Ferror(sfd)) {
571         (void) Fwrite(sig, sizeof(char), siglen, sfd);
572         (void) Fclose(sfd);
573     }
574 #else
575     {   FD_t sfd;
576         if (!makeTempFile(NULL, &sigfile, &sfd)) {
577             (void) Fwrite(sig, sizeof(*sig), siglen, sfd);
578             (void) Fclose(sfd);
579             sfd = NULL;
580         }
581     }
582 #endif
583     if (sigfile == NULL)
584         return RPMSIG_BAD;
585
586     /* Now run PGP */
587     outpipe[0] = outpipe[1] = 0;
588     (void) pipe(outpipe);
589
590     if (!(pid = fork())) {
591         const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
592
593         (void) close(outpipe[0]);
594         (void) close(STDOUT_FILENO);    /* XXX unnecessary */
595         (void) dup2(outpipe[1], STDOUT_FILENO);
596
597         if (pgp_path && *pgp_path != '%')
598             (void) dosetenv("PGPPATH", pgp_path, 1);
599
600         switch (pgpVer) {
601         case PGP_5:
602             /* Some output (in particular "This signature applies to */
603             /* another message") is _always_ written to stderr; we   */
604             /* want to catch that output, so dup stdout to stderr:   */
605         {   int save_stderr = dup(2);
606             (void) dup2(1, 2);
607             (void) execlp(path, "pgpv", "+batchmode=on", "+verbose=0",
608                    /* Write "Good signature..." to stdout: */
609                    "+OutputInformationFD=1",
610                    /* Write "WARNING: ... is not trusted to... to stdout: */
611                    "+OutputWarningFD=1",
612                    sigfile, "-o", datafile, NULL);
613             /* Restore stderr so we can print the error message below. */
614             (void) dup2(save_stderr, 2);
615             (void) close(save_stderr);
616         }   break;
617         case PGP_2:
618             (void) execlp(path, "pgp", "+batchmode=on", "+verbose=0",
619                    sigfile, datafile, NULL);
620             break;
621         case PGP_UNKNOWN:
622         case PGP_NOTDETECTED:
623             break;
624         }
625
626         rpmError(RPMERR_EXEC,
627                  _("Could not run pgp.  Use --nopgp to skip PGP checks.\n"));
628         _exit(RPMERR_EXEC);
629     }
630
631     (void) close(outpipe[1]);
632     file = fdopen(outpipe[0], "r");
633     result[0] = '\0';
634     if (file) {
635         while (fgets(buf, 1024, file)) {
636             if (strncmp("File '", buf, 6) &&
637                 strncmp("Text is assu", buf, 12) &&
638                 strncmp("This signature applies to another message", buf, 41) &&
639                 buf[0] != '\n') {
640                 strcat(result, buf);
641             }
642             if (!strncmp("WARNING: Can't find the right public key", buf, 40))
643                 res = RPMSIG_NOKEY;
644             else if (!strncmp("Signature by unknown keyid:", buf, 27))
645                 res = RPMSIG_NOKEY;
646             else if (!strncmp("WARNING: The signing key is not trusted", buf, 39))
647                 res = RPMSIG_NOTTRUSTED;
648             else if (!strncmp("Good signature", buf, 14))
649                 res = RPMSIG_OK;
650         }
651         (void) fclose(file);
652     }
653
654     (void) waitpid(pid, &status, 0);
655     if (sigfile) (void) unlink(sigfile);
656     sigfile = _free(sigfile);
657     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
658         res = RPMSIG_BAD;
659     }
660   }
661
662     if (res != resbc) {
663         fprintf(stderr, "=============================== RSA verify %s: rc %d\n",
664                         datafile, resbc);
665         (void) pgpPrtPkts(sig, siglen, dig, 1);
666         printf("\t n = ");      (void) fflush(stdout);
667                 mp32println(dig->rsa_pk.n.size, dig->rsa_pk.n.modl);
668         printf("\t e = ");      (void) fflush(stdout);
669                 mp32println(dig->rsa_pk.e.size, dig->rsa_pk.e.data);
670         printf("\t c = ");      (void) fflush(stdout);
671                 mp32println(dig->c.size, dig->c.data);
672         printf("\t m = ");      (void)fflush(stdout);
673                 mp32println(dig->rsahm.size, dig->rsahm.data);
674     }
675 #endif  /* DYING */
676
677     return res;
678 }
679
680 static rpmVerifySignatureReturn
681 verifyGPGSignature(/*@unused@*/ const char * datafile,
682                 /*@unused@*/ const byte * sig,
683                 /*@unused@*/ int siglen,
684                 const rpmDigest dig, /*@out@*/ char * result)
685         /*@modifies *result @*/
686 {
687     int res, resbc;
688
689     *result = '\0';
690
691     /*@-type@*/
692     if (dsavrfy(&dig->p, &dig->q, &dig->g, &dig->hm, &dig->y, &dig->r, &dig->s))
693         res = resbc = RPMSIG_OK;
694     else
695         res = resbc = RPMSIG_BAD;
696     /*@=type@*/
697
698 #ifdef DYING
699   {
700     int pid, status, outpipe[2];
701 /*@only@*/ /*@null@*/ const char * sigfile = NULL;
702     byte buf[BUFSIZ];
703     FILE *file;
704     int res = RPMSIG_OK;
705
706 /*@-type@*/
707 /*@=type@*/
708
709     /* Write out the signature */
710 #ifdef  DYING
711   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
712     sigfile = tempnam(tmppath, "rpmsig");
713     tmppath = _free(tmppath);
714   }
715     sfd = Fopen(sigfile, "w.fdio");
716     if (sfd != NULL && !Ferror(sfd)) {
717         (void) Fwrite(sig, sizeof(char), siglen, sfd);
718         (void) Fclose(sfd);
719     }
720 #else
721     {   FD_t sfd;
722         if (!makeTempFile(NULL, &sigfile, &sfd)) {
723             (void) Fwrite(sig, sizeof(*sig), siglen, sfd);
724             (void) Fclose(sfd);
725             sfd = NULL;
726         }
727     }
728 #endif
729     if (sigfile == NULL)
730         return RPMSIG_BAD;
731
732     /* Now run GPG */
733     outpipe[0] = outpipe[1] = 0;
734     (void) pipe(outpipe);
735
736     if (!(pid = fork())) {
737         const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
738
739         (void) close(outpipe[0]);
740         /* gpg version 0.9 sends its output to stderr. */
741         (void) dup2(outpipe[1], STDERR_FILENO);
742
743         if (gpg_path && *gpg_path != '%')
744             (void) dosetenv("GNUPGHOME", gpg_path, 1);
745
746         (void) execlp("gpg", "gpg",
747                "--batch", "--no-verbose",
748                "--verify", sigfile, datafile,
749                NULL);
750         rpmError(RPMERR_EXEC,
751                  _("Could not run gpg.  Use --nogpg to skip GPG checks.\n"));
752         _exit(RPMERR_EXEC);
753     }
754
755     (void) close(outpipe[1]);
756     file = fdopen(outpipe[0], "r");
757     result[0] = '\0';
758     if (file) {
759         while (fgets(buf, 1024, file)) {
760             strcat(result, buf);
761             if (!xstrncasecmp("gpg: Can't check signature: Public key not found", buf, 48)) {
762                 res = RPMSIG_NOKEY;
763             }
764         }
765         (void) fclose(file);
766     }
767
768     (void) waitpid(pid, &status, 0);
769     if (sigfile) (void) unlink(sigfile);
770     sigfile = _free(sigfile);
771     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
772         res = RPMSIG_BAD;
773     }
774
775   }
776
777     if (res != resbc) {
778         fprintf(stderr, "=============================== DSA verify %s: rc %d\n",
779                         datafile, resbc);
780         (void) pgpPrtPkts(sig, siglen, dig, 1);
781         printf("\t p = ");      (void) fflush(stdout);
782                 mp32println(dig->p.size, dig->p.modl);
783         printf("\t q = ");      (void) fflush(stdout);
784                 mp32println(dig->q.size, dig->q.modl);
785         printf("\t g = ");      (void) fflush(stdout);
786                 mp32println(dig->g.size, dig->g.data);
787         printf("\t y = ");      (void) fflush(stdout);
788                 mp32println(dig->y.size, dig->y.data);
789         printf("\t r = ");      (void) fflush(stdout);
790                 mp32println(dig->r.size, dig->r.data);
791         printf("\t s = ");      (void) fflush(stdout);
792                 mp32println(dig->s.size, dig->s.data);
793         printf("\thm = ");      (void) fflush(stdout);
794                 mp32println(dig->hm.size, dig->hm.data);
795     }
796 #endif
797
798     return res;
799 }
800
801 static int checkPassPhrase(const char * passPhrase, const int sigTag)
802         /*@globals rpmGlobalMacroContext,
803                 fileSystem @*/
804         /*@modifies fileSystem @*/
805 {
806     int passPhrasePipe[2];
807     int pid, status;
808     int fd;
809
810     passPhrasePipe[0] = passPhrasePipe[1] = 0;
811     (void) pipe(passPhrasePipe);
812     if (!(pid = fork())) {
813         (void) close(STDIN_FILENO);
814         (void) close(STDOUT_FILENO);
815         (void) close(passPhrasePipe[1]);
816         /*@-internalglobs@*/ /* FIX: shrug */
817         if (! rpmIsVerbose()) {
818             (void) close(STDERR_FILENO);
819         }
820         /*@=internalglobs@*/
821         if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
822             (void) dup2(fd, STDIN_FILENO);
823             (void) close(fd);
824         }
825         if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
826             (void) dup2(fd, STDOUT_FILENO);
827             (void) close(fd);
828         }
829         (void) dup2(passPhrasePipe[0], 3);
830
831         switch (sigTag) {
832         case RPMSIGTAG_GPG:
833         {   const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
834             const char *name = rpmExpand("%{_gpg_name}", NULL);
835             if (gpg_path && *gpg_path != '%')
836                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
837             (void) execlp("gpg", "gpg",
838                    "--batch", "--no-verbose", "--passphrase-fd", "3",
839                    "-u", name, "-so", "-",
840                    NULL);
841             rpmError(RPMERR_EXEC, _("Couldn't exec gpg\n"));
842             _exit(RPMERR_EXEC);
843         }   /*@notreached@*/ break;
844         case RPMSIGTAG_PGP5:    /* XXX legacy */
845         case RPMSIGTAG_PGP:
846         {   const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
847             const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
848             const char *path;
849             pgpVersion pgpVer;
850
851             (void) dosetenv("PGPPASSFD", "3", 1);
852             if (pgp_path && *pgp_path != '%')
853                 (void) dosetenv("PGPPATH", pgp_path, 1);
854
855             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
856                 switch(pgpVer) {
857                 case PGP_2:
858                     (void) execlp(path, "pgp", "+batchmode=on", "+verbose=0",
859                         name, "-sf", NULL);
860                     /*@innerbreak@*/ break;
861                 case PGP_5:     /* XXX legacy */
862                     (void) execlp(path,"pgps", "+batchmode=on", "+verbose=0",
863                         name, "-f", NULL);
864                     /*@innerbreak@*/ break;
865                 case PGP_UNKNOWN:
866                 case PGP_NOTDETECTED:
867                     /*@innerbreak@*/ break;
868                 }
869             }
870             rpmError(RPMERR_EXEC, _("Couldn't exec pgp\n"));
871             _exit(RPMERR_EXEC);
872         }   /*@notreached@*/ break;
873         default: /* This case should have been screened out long ago. */
874             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
875             _exit(RPMERR_SIGGEN);
876             /*@notreached@*/ break;
877         }
878     }
879
880     (void) close(passPhrasePipe[0]);
881     (void) write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
882     (void) write(passPhrasePipe[1], "\n", 1);
883     (void) close(passPhrasePipe[1]);
884
885     (void)waitpid(pid, &status, 0);
886     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
887         return 1;
888     }
889
890     /* passPhrase is good */
891     return 0;
892 }
893
894 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
895 {
896     char *pass;
897     int aok;
898
899     switch (sigTag) {
900     case RPMSIGTAG_GPG:
901       { const char *name = rpmExpand("%{_gpg_name}", NULL);
902         aok = (name && *name != '%');
903         name = _free(name);
904       }
905         if (!aok) {
906             rpmError(RPMERR_SIGGEN,
907                 _("You must set \"%%_gpg_name\" in your macro file\n"));
908             return NULL;
909         }
910         break;
911     case RPMSIGTAG_PGP5:        /* XXX legacy */
912     case RPMSIGTAG_PGP:
913       { const char *name = rpmExpand("%{_pgp_name}", NULL);
914         aok = (name && *name != '%');
915         name = _free(name);
916       }
917         if (!aok) {
918             rpmError(RPMERR_SIGGEN,
919                 _("You must set \"%%_pgp_name\" in your macro file\n"));
920             return NULL;
921         }
922         break;
923     default:
924         /* Currently the calling function (rpm.c:main) is checking this and
925          * doing a better job.  This section should never be accessed.
926          */
927         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
928         return NULL;
929         /*@notreached@*/ break;
930     }
931
932     pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
933
934     if (checkPassPhrase(pass, sigTag))
935         return NULL;
936
937     return pass;
938 }
939
940 rpmVerifySignatureReturn
941 rpmVerifySignature(const char * file, int_32 sigTag, const void * sig,
942                 int siglen, const rpmDigest dig, char * result)
943 {
944     switch (sigTag) {
945     case RPMSIGTAG_SIZE:
946         return verifySizeSignature(file, *(int_32 *)sig, result);
947         /*@notreached@*/ break;
948     case RPMSIGTAG_MD5:
949         return verifyMD5Signature(file, sig, siglen, dig, result, mdbinfile);
950         /*@notreached@*/ break;
951     case RPMSIGTAG_PGP5:        /* XXX legacy */
952     case RPMSIGTAG_PGP:
953         return verifyPGPSignature(file, sig, siglen, dig, result);
954         /*@notreached@*/ break;
955     case RPMSIGTAG_GPG:
956         return verifyGPGSignature(file, sig, siglen, dig, result);
957         /*@notreached@*/ break;
958     case RPMSIGTAG_LEMD5_1:
959     case RPMSIGTAG_LEMD5_2:
960     default:
961         sprintf(result, "Do not know how to verify sig type %d\n", sigTag);
962         return RPMSIG_UNKNOWN;
963     }
964     /*@notreached@*/
965     return RPMSIG_OK;
966 }
967 /*@=mods@*/