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