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