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