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