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