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