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