rpm  5.2.1
signature.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <rpmio.h>
8 #include <rpmurl.h>
9 #include <rpmcb.h> /* XXX rpmIsVerbose() */
10 #define _RPMPGP_INTERNAL
11 #include <rpmpgp.h>
12 #include <rpmmacro.h> /* XXX for rpmGetPath() */
13 #include <rpmku.h>
14 
15 #include <rpmtag.h>
16 #include "rpmdb.h"
17 #include <pkgio.h> /* XXX expects <rpmts.h> */
18 #include "legacy.h" /* XXX for dodogest() */
19 #include "signature.h"
20 
21 #include "debug.h"
22 
23 /*@access FD_t@*/ /* XXX ufdio->read arg1 is void ptr */
24 /*@access Header@*/ /* XXX compared with NULL */
25 /*@access DIGEST_CTX@*/ /* XXX compared with NULL */
26 /*@access pgpDig@*/
27 /*@access pgpDigParams@*/
28 
29 int rpmTempFile(const char * prefix, const char ** fnptr, void * fdptr)
30 {
31  const char * tpmacro = "%{?_tmppath}%{!?_tmppath:/var/tmp/}";
32  const char * tempfn = NULL;
33  const char * tfn = NULL;
34  static int _initialized = 0;
35  int temput;
36  FD_t fd = NULL;
37  unsigned int ran;
38 
39  if (!prefix) prefix = "";
40 
41  /* Create the temp directory if it doesn't already exist. */
42  if (!_initialized) {
43  _initialized = 1;
44  tempfn = rpmGenPath(prefix, tpmacro, NULL);
45  if (rpmioMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1))
46  goto errxit;
47  }
48 
49  /* XXX should probably use mkstemp here */
50  ran = (unsigned) time(NULL);
51  srand(ran);
52  ran = rand() % 100000;
53 
54  /* maybe this should use link/stat? */
55 
56  do {
57  char tfnbuf[64];
58 #ifndef NOTYET
59  sprintf(tfnbuf, "rpm-tmp.%u", ran++);
60  tempfn = _free(tempfn);
61  tempfn = rpmGenPath(prefix, tpmacro, tfnbuf);
62 #else
63  strcpy(tfnbuf, "rpm-tmp.XXXXXX");
64  tempfn = _free(tempfn);
65  tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf));
66 #endif
67 
68  temput = urlPath(tempfn, &tfn);
69  if (*tfn == '\0') goto errxit;
70 
71  switch (temput) {
72  case URL_IS_DASH:
73  case URL_IS_HKP:
74  goto errxit;
75  /*@notreached@*/ /*@switchbreak@*/ break;
76  case URL_IS_HTTPS:
77  case URL_IS_HTTP:
78  case URL_IS_FTP:
79  default:
80  /*@switchbreak@*/ break;
81  }
82 
83  fd = Fopen(tempfn, "w+x.fdio");
84  /* XXX FIXME: errno may not be correct for ufdio */
85  } while ((fd == NULL || Ferror(fd)) && errno == EEXIST);
86 
87  if (fd == NULL || Ferror(fd)) {
88  rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tempfn);
89  goto errxit;
90  }
91 
92  switch(temput) {
93  case URL_IS_PATH:
94  case URL_IS_UNKNOWN:
95  { struct stat sb, sb2;
96  if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) {
97  rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
98  goto errxit;
99  }
100 
101  if (sb.st_nlink != 1) {
102  rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
103  goto errxit;
104  }
105 
106  if (fstat(Fileno(fd), &sb2) == 0) {
107  if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) {
108  rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
109  goto errxit;
110  }
111  }
112  } break;
113  default:
114  break;
115  }
116 
117  if (fnptr)
118  *fnptr = tempfn;
119  else
120  tempfn = _free(tempfn);
121  if (fdptr)
122  *(FD_t *)fdptr = fd;
123 
124  return 0;
125 
126 errxit:
127  tempfn = _free(tempfn);
128  if (fnptr)
129  *fnptr = NULL;
130  /*@-usereleased@*/
131  if (fd != NULL) (void) Fclose(fd);
132  /*@=usereleased@*/
133  return 1;
134 }
135 
136 
146 static int makeGPGSignature(const char * file, rpmSigTag * sigTagp,
147  /*@out@*/ rpmuint8_t ** pktp, /*@out@*/ rpmuint32_t * pktlenp,
148  /*@null@*/ const char * passPhrase)
149  /*@globals rpmGlobalMacroContext, h_errno,
150  fileSystem, internalState @*/
151  /*@modifies *pktp, *pktlenp, *sigTagp, rpmGlobalMacroContext,
152  fileSystem, internalState @*/
153 {
154  char * sigfile = alloca(strlen(file)+sizeof(".sig"));
155  pid_t pid;
156  int status;
157  int inpipe[2];
158  FILE * fpipe;
159  struct stat st;
160  const char * cmd;
161  char *const *av;
162  pgpDig dig = NULL;
163  pgpDigParams sigp = NULL;
164  const char * pw = NULL;
165  int rc;
166 
167  (void) stpcpy( stpcpy(sigfile, file), ".sig");
168 
169  addMacro(NULL, "__plaintext_filename", NULL, file, -1);
170  addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
171 
172  inpipe[0] = inpipe[1] = 0;
173  if (pipe(inpipe) < 0) {
174  rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
175  return 1;
176  }
177 
178  if (!(pid = fork())) {
179  const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
180 
181  (void) dup2(inpipe[0], 3);
182  (void) close(inpipe[1]);
183 
184  if (gpg_path && *gpg_path != '\0')
185  (void) setenv("GNUPGHOME", gpg_path, 1);
186 
187  unsetenv("MALLOC_CHECK_");
188  cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
189  rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
190  if (!rc)
191  rc = execve(av[0], av+1, environ);
192 
193  rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
194  strerror(errno));
195  _exit(EXIT_FAILURE);
196  }
197 
198  delMacro(NULL, "__plaintext_filename");
199  delMacro(NULL, "__signature_filename");
200 
201  pw = rpmkuPassPhrase(passPhrase);
202  if (pw == NULL) {
203  rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
204  strerror(errno));
205  return 1;
206  }
207 
208  fpipe = fdopen(inpipe[1], "w");
209  (void) close(inpipe[0]);
210  if (fpipe) {
211  fprintf(fpipe, "%s\n", (pw ? pw : ""));
212  (void) fclose(fpipe);
213  }
214 
215  if (pw != NULL) {
216  (void) memset((void *)pw, 0, strlen(pw));
217  pw = _free(pw);
218  }
219 
220 /*@+longunsignedintegral@*/
221  (void) waitpid(pid, &status, 0);
222 /*@=longunsignedintegral@*/
223  if (!WIFEXITED(status) || WEXITSTATUS(status)) {
224  rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
225  return 1;
226  }
227 
228  if (Stat(sigfile, &st)) {
229  /* GPG failed to write signature */
230  if (sigfile) (void) Unlink(sigfile); /* Just in case */
231  rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n"));
232  return 1;
233  }
234 
235  *pktlenp = (rpmuint32_t)st.st_size;
236  rpmlog(RPMLOG_DEBUG, D_("GPG sig size: %u\n"), (unsigned)*pktlenp);
237  *pktp = xmalloc(*pktlenp);
238 
239  { FD_t fd;
240 
241  rc = 0;
242  fd = Fopen(sigfile, "r.ufdio");
243  if (fd != NULL && !Ferror(fd)) {
244  rc = (int) Fread(*pktp, sizeof((*pktp)[0]), *pktlenp, fd);
245  if (sigfile) (void) Unlink(sigfile);
246  (void) Fclose(fd);
247  }
248  if ((rpmuint32_t)rc != *pktlenp) {
249  *pktp = _free(*pktp);
250  rpmlog(RPMLOG_ERR, _("unable to read the signature\n"));
251  return 1;
252  }
253  }
254 
255  rpmlog(RPMLOG_DEBUG, D_("Got %u bytes of GPG sig\n"), (unsigned)*pktlenp);
256 
257  /* Parse the signature, change signature tag as appropriate. */
258  dig = pgpDigNew(0);
259 
260  (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
261  sigp = pgpGetSignature(dig);
262 
263  /* Identify the type of signature being returned. */
264  switch (*sigTagp) {
265  default:
266 assert(0); /* XXX never happens. */
267  /*@notreached@*/ break;
268  case RPMSIGTAG_SIZE:
269  case RPMSIGTAG_MD5:
270  case RPMSIGTAG_SHA1:
271  break;
272  case RPMSIGTAG_DSA:
273  /* XXX check hash algorithm too? */
274  if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA)
275  *sigTagp = RPMSIGTAG_RSA;
276  break;
277  case RPMSIGTAG_RSA:
278  if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA)
279  *sigTagp = RPMSIGTAG_DSA;
280  break;
281  }
282 
283  dig = pgpDigFree(dig, "makeGPGSignature");
284 
285  return 0;
286 }
287 
296 /*@-mustmod@*/ /* sigh is modified */
297 static int makeHDRSignature(Header sigh, const char * file, rpmSigTag sigTag,
298  /*@null@*/ const char * passPhrase)
299  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
300  /*@modifies sigh, sigTag, rpmGlobalMacroContext, fileSystem, internalState @*/
301 {
302  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
303  Header h = NULL;
304  FD_t fd = NULL;
305  rpmuint8_t * pkt;
306  rpmuint32_t pktlen;
307  const char * fn = NULL;
308  const char * msg;
309  rpmRC rc;
310  int ret = -1; /* assume failure. */
311  int xx;
312 
313  switch (sigTag) {
314  default:
315 assert(0); /* XXX never happens. */
316  /*@notreached@*/ break;
317  case RPMSIGTAG_SIZE:
318  case RPMSIGTAG_MD5:
319  case RPMSIGTAG_PGP5: /* XXX legacy */
320  case RPMSIGTAG_PGP:
321  case RPMSIGTAG_GPG:
322  goto exit;
323  /*@notreached@*/ break;
324  case RPMSIGTAG_SHA1:
325  { const char * SHA1 = NULL;
326  fd = Fopen(file, "r.fdio");
327  if (fd == NULL || Ferror(fd))
328  goto exit;
329  { const char item[] = "Header";
330  msg = NULL;
331  rc = rpmpkgRead(item, fd, &h, &msg);
332  if (rc != RPMRC_OK) {
333  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
334  msg = _free(msg);
335  goto exit;
336  }
337  msg = _free(msg);
338  }
339  (void) Fclose(fd); fd = NULL;
340 
342  unsigned char * hmagic = NULL;
343  size_t nmagic = 0;
344  DIGEST_CTX ctx;
345 
347  if (!headerGet(h, he, 0) || he->p.ptr == NULL)
348  {
349  (void)headerFree(h);
350  h = NULL;
351  goto exit;
352  }
353  (void) headerGetMagic(NULL, &hmagic, &nmagic);
355  if (hmagic && nmagic > 0)
356  (void) rpmDigestUpdate(ctx, hmagic, nmagic);
357  (void) rpmDigestUpdate(ctx, he->p.ptr, he->c);
358  (void) rpmDigestFinal(ctx, &SHA1, NULL, 1);
359  he->p.ptr = _free(he->p.ptr);
360  }
361  (void)headerFree(h);
362  h = NULL;
363 
364  if (SHA1 == NULL)
365  goto exit;
366  he->tag = (rpmTag) RPMSIGTAG_SHA1;
367  he->t = RPM_STRING_TYPE;
368  he->p.str = SHA1;
369  he->c = 1;
370  xx = headerPut(sigh, he, 0);
371  SHA1 = _free(SHA1);
372  if (!xx)
373  goto exit;
374  ret = 0;
375  } break;
376  case RPMSIGTAG_DSA:
377  fd = Fopen(file, "r.fdio");
378  if (fd == NULL || Ferror(fd))
379  goto exit;
380  { const char item[] = "Header";
381  msg = NULL;
382  rc = rpmpkgRead(item, fd, &h, &msg);
383  if (rc != RPMRC_OK) {
384  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
385  msg = _free(msg);
386  goto exit;
387  }
388  msg = _free(msg);
389  }
390  (void) Fclose(fd); fd = NULL;
391 
392  if (rpmTempFile(NULL, &fn, &fd))
393  goto exit;
394  { const char item[] = "Header";
395  msg = NULL;
396  rc = rpmpkgWrite(item, fd, h, &msg);
397  if (rc != RPMRC_OK) {
398  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
399  msg = _free(msg);
400  goto exit;
401  }
402  msg = _free(msg);
403  }
404  (void) Fclose(fd); fd = NULL;
405 
406  if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase))
407  goto exit;
408  he->tag = (rpmTag) sigTag;
409  he->t = RPM_BIN_TYPE;
410  he->p.ptr = pkt;
411  he->c = pktlen;
412  xx = headerPut(sigh, he, 0);
413  if (!xx)
414  goto exit;
415  ret = 0;
416  break;
417  }
418 
419 exit:
420  if (fn) {
421  (void) Unlink(fn);
422  fn = _free(fn);
423  }
424  (void)headerFree(h);
425  h = NULL;
426  if (fd != NULL) (void) Fclose(fd);
427  return ret;
428 }
429 /*@=mustmod@*/
430 
431 int rpmAddSignature(Header sigh, const char * file, rpmSigTag sigTag,
432  const char * passPhrase)
433 {
434  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
435  struct stat st;
436  rpmuint8_t * pkt;
437  rpmuint32_t pktlen;
438  int ret = -1; /* assume failure. */
439  int xx;
440 
441  switch (sigTag) {
442  default:
443 assert(0); /* XXX never happens. */
444  /*@notreached@*/ break;
445  case RPMSIGTAG_SIZE:
446  if (Stat(file, &st) != 0)
447  break;
448  pktlen = (rpmuint32_t)st.st_size;
449  he->tag = (rpmTag) sigTag;
450  he->t = RPM_UINT32_TYPE;
451  he->p.ui32p = &pktlen;
452  he->c = 1;
453 /*@-compmempass@*/
454  xx = headerPut(sigh, he, 0);
455 /*@=compmempass@*/
456  if (!xx)
457  break;
458  ret = 0;
459  break;
460  case RPMSIGTAG_MD5:
461  pktlen = 128/8;
462  pkt = memset(alloca(pktlen), 0, pktlen);
463  if (dodigest(PGPHASHALGO_MD5, file, (unsigned char *)pkt, 0, NULL))
464  break;
465  he->tag = (rpmTag) sigTag;
466  he->t = RPM_BIN_TYPE;
467  he->p.ptr = pkt;
468  he->c = pktlen;
469  xx = headerPut(sigh, he, 0);
470  if (!xx)
471  break;
472  ret = 0;
473  break;
474  case RPMSIGTAG_GPG:
475  ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase);
476  break;
477  case RPMSIGTAG_RSA:
478  case RPMSIGTAG_DSA:
479  case RPMSIGTAG_SHA1:
480  ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
481  break;
482  }
483 
484  return ret;
485 }
486 
487 int rpmCheckPassPhrase(const char * passPhrase)
488 {
489  const char *pw;
490  int p[2];
491  pid_t pid;
492  int status;
493  int rc;
494  int xx;
495 
496  p[0] = p[1] = 0;
497  xx = pipe(p);
498 
499  if (!(pid = fork())) {
500  const char * cmd;
501  char *const *av;
502  int fdno;
503 
504  xx = close(STDIN_FILENO);
505  xx = close(STDOUT_FILENO);
506  xx = close(p[1]);
507  if (!rpmIsVerbose())
508  xx = close(STDERR_FILENO);
509  if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
510  xx = dup2(fdno, STDIN_FILENO);
511  xx = close(fdno);
512  }
513  if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
514  xx = dup2(fdno, STDOUT_FILENO);
515  xx = close(fdno);
516  }
517  xx = dup2(p[0], 3);
518 
519  unsetenv("MALLOC_CHECK_");
520  { const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
521 
522  if (gpg_path && *gpg_path != '\0')
523  (void) setenv("GNUPGHOME", gpg_path, 1);
524 
525  cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
526  rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
527  if (!rc)
528  rc = execve(av[0], av+1, environ);
529 
530  rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
531  strerror(errno));
532  }
533  }
534 
535  pw = rpmkuPassPhrase(passPhrase);
536  if (pw == NULL) {
537  rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
538  strerror(errno));
539  return 1;
540  }
541 
542  xx = close(p[0]);
543  xx = (int) write(p[1], pw, strlen(pw));
544  xx = (int) write(p[1], "\n", 1);
545  xx = close(p[1]);
546 
547  if (pw != NULL) {
548  (void) memset((void *)pw, 0, strlen(pw));
549  pw = _free(pw);
550  }
551 
552 /*@+longunsignedintegral@*/
553  (void) waitpid(pid, &status, 0);
554 /*@=longunsignedintegral@*/
555 
556  return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
557 }
558 
559 static /*@observer@*/ const char * rpmSigString(rpmRC res)
560  /*@*/
561 {
562  const char * str;
563  switch (res) {
564  case RPMRC_OK: str = "OK"; break;
565  case RPMRC_FAIL: str = "BAD"; break;
566  case RPMRC_NOKEY: str = "NOKEY"; break;
567  case RPMRC_NOTTRUSTED: str = "NOTRUSTED"; break;
568  default:
569  case RPMRC_NOTFOUND: str = "UNKNOWN"; break;
570  }
571  return str;
572 }
573 
574 static rpmRC
575 verifySize(const pgpDig dig, /*@out@*/ char * t)
576  /*@modifies *t @*/
577 {
578  const void * sig = pgpGetSig(dig);
579  rpmRC res;
580  rpmuint32_t size = 0xffffffff;
581 
582  *t = '\0';
583  t = stpcpy(t, _("Header+Payload size: "));
584 
585  if (sig == NULL || dig == NULL || dig->nbytes == 0) {
586  res = RPMRC_NOKEY;
587  t = stpcpy(t, rpmSigString(res));
588  goto exit;
589  }
590 
591  memcpy(&size, sig, sizeof(size));
592 
593  if (size !=(rpmuint32_t) dig->nbytes) {
594  res = RPMRC_FAIL;
595  t = stpcpy(t, rpmSigString(res));
596  sprintf(t, " Expected(%u) != (%u)\n", (unsigned)size, (unsigned)dig->nbytes);
597  } else {
598  res = RPMRC_OK;
599  t = stpcpy(t, rpmSigString(res));
600  sprintf(t, " (%u)", (unsigned)dig->nbytes);
601  }
602 
603 exit:
604  return res;
605 }
606 
607 static rpmRC
608 verifyMD5(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX md5ctx)
609  /*@globals internalState @*/
610  /*@modifies *t, internalState @*/
611 {
612  const void * sig = pgpGetSig(dig);
613  rpmuint32_t siglen = pgpGetSiglen(dig);
614  rpmRC res;
615  rpmuint8_t * md5sum = NULL;
616  size_t md5len = 0;
617 
618 assert(dig != NULL);
619 assert(md5ctx != NULL);
620 assert(sig != NULL);
621 
622  *t = '\0';
623 
624  /* Identify the hash. */
625  t = stpcpy(t, rpmDigestName(md5ctx));
626  t = stpcpy(t, _(" digest: "));
627 
628  if (sig == NULL) { /* XXX can't happen, DYING */
629  res = RPMRC_NOKEY;
630  t = stpcpy(t, rpmSigString(res));
631  goto exit;
632  }
633 
634  { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
635  (void) rpmswEnter(op, 0);
636  (void) rpmDigestFinal(rpmDigestDup(md5ctx), &md5sum, &md5len, 0);
637  (void) rpmswExit(op, 0);
638  if (op != NULL) op->count--; /* XXX one too many */
639  }
640 
641  if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
642  res = RPMRC_FAIL;
643  t = stpcpy(t, rpmSigString(res));
644  t = stpcpy(t, " Expected(");
645  (void) pgpHexCvt(t, sig, siglen);
646  t += strlen(t);
647  t = stpcpy(t, ") != (");
648  } else {
649  res = RPMRC_OK;
650  t = stpcpy(t, rpmSigString(res));
651  t = stpcpy(t, " (");
652  }
653  (void) pgpHexCvt(t, md5sum, md5len);
654  t += strlen(t);
655  t = stpcpy(t, ")");
656 
657 exit:
658  md5sum = _free(md5sum);
659  return res;
660 }
661 
669 static rpmRC
670 verifySHA1(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX shactx)
671  /*@globals internalState @*/
672  /*@modifies *t, internalState @*/
673 {
674  const void * sig = pgpGetSig(dig);
675 #ifdef NOTYET
676  rpmuint32_t siglen = pgpGetSiglen(dig);
677 #endif
678  rpmRC res;
679  const char * SHA1 = NULL;
680 
681 assert(dig != NULL);
682 assert(shactx != NULL);
683 assert(sig != NULL);
684 
685  *t = '\0';
686  t = stpcpy(t, _("Header "));
687 
688  /* Identify the hash. */
689  t = stpcpy(t, rpmDigestName(shactx));
690  t = stpcpy(t, _(" digest: "));
691 
692  if (sig == NULL) { /* XXX can't happen, DYING */
693  res = RPMRC_NOKEY;
694  t = stpcpy(t, rpmSigString(res));
695  goto exit;
696  }
697 
698  { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
699  (void) rpmswEnter(op, 0);
700  (void) rpmDigestFinal(rpmDigestDup(shactx), &SHA1, NULL, 1);
701  (void) rpmswExit(op, 0);
702  }
703 
704  if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
705  res = RPMRC_FAIL;
706  t = stpcpy(t, rpmSigString(res));
707  t = stpcpy(t, " Expected(");
708  t = stpcpy(t, sig);
709  t = stpcpy(t, ") != (");
710  } else {
711  res = RPMRC_OK;
712  t = stpcpy(t, rpmSigString(res));
713  t = stpcpy(t, " (");
714  }
715  if (SHA1)
716  t = stpcpy(t, SHA1);
717  t = stpcpy(t, ")");
718 
719 exit:
720  SHA1 = _free(SHA1);
721  return res;
722 }
723 
731 static rpmRC
732 verifyRSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX rsactx)
733  /*@globals internalState @*/
734  /*@modifies dig, *t, internalState */
735 {
736  const void * sig = pgpGetSig(dig);
737 #ifdef NOTYET
738  rpmuint32_t siglen = pgpGetSiglen(dig);
739 #endif
740  pgpDigParams sigp = pgpGetSignature(dig);
741  rpmRC res = RPMRC_OK;
742  int xx;
743 
744 assert(dig != NULL);
745 assert(rsactx != NULL);
746 assert(sigp != NULL);
747 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA);
748 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(rsactx));
749 assert(pgpGetSigtag(dig) == RPMSIGTAG_RSA);
750 assert(sig != NULL);
751 
752  *t = '\0';
753  if (dig->hdrctx == rsactx)
754  t = stpcpy(t, _("Header "));
755 
756  /* Identify the signature version. */
757  *t++ = 'V';
758  switch (sigp->version) {
759  case 3: *t++ = '3'; break;
760  case 4: *t++ = '4'; break;
761  }
762 
763  /* Identify the RSA/hash. */
764  { const char * hashname = rpmDigestName(rsactx);
765  t = stpcpy(t, " RSA");
766  if (strcmp(hashname, "UNKNOWN")) {
767  *t++ = '/';
768  t = stpcpy(t, hashname);
769  }
770  }
771  t = stpcpy(t, _(" signature: "));
772 
773  { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
774  DIGEST_CTX ctx = rpmDigestDup(rsactx);
775 
776  (void) rpmswEnter(op, 0);
777  if (sigp->hash != NULL)
778  xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
779 
780  if (sigp->version == (rpmuint8_t) 4) {
781  rpmuint32_t nb = (rpmuint32_t) sigp->hashlen;
782  rpmuint8_t trailer[6];
783  nb = (rpmuint32_t) htonl(nb);
784  trailer[0] = sigp->version;
785  trailer[1] = (rpmuint8_t)0xff;
786  memcpy(trailer+2, &nb, sizeof(nb));
787  xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
788  }
789  (void) rpmswExit(op, sigp->hashlen);
790  if (op != NULL) op->count--; /* XXX one too many */
791 
792  if ((xx = pgpImplSetRSA(ctx, dig, sigp)) != 0) {
793  res = RPMRC_FAIL;
794  goto exit;
795  }
796  }
797 
798  /* Retrieve the matching public key. */
799  res = pgpFindPubkey(dig);
800  if (res != RPMRC_OK)
801  goto exit;
802 
803  /* Verify the RSA signature. */
804  { rpmop op = pgpStatsAccumulator(dig, 11); /* RPMTS_OP_SIGNATURE */
805  (void) rpmswEnter(op, 0);
806  xx = pgpImplVerifyRSA(dig);
807  (void) rpmswExit(op, 0);
808  res = (xx ? RPMRC_OK : RPMRC_FAIL);
809  }
810 
811 exit:
812  /* Identify the pubkey fingerprint. */
813  t = stpcpy(t, rpmSigString(res));
814  if (sigp != NULL) {
815  t = stpcpy(t, ", key ID ");
816  (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
817  t += strlen(t);
818  }
819  return res;
820 }
821 
829 static rpmRC
830 verifyDSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX dsactx)
831  /*@globals internalState @*/
832  /*@modifies dig, *t, internalState */
833 {
834  const void * sig = pgpGetSig(dig);
835 #ifdef NOTYET
836  rpmuint32_t siglen = pgpGetSiglen(dig);
837 #endif
838  pgpDigParams sigp = pgpGetSignature(dig);
839  rpmRC res;
840  int xx;
841 
842 assert(dig != NULL);
843 assert(dsactx != NULL);
844 assert(sigp != NULL);
845 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA);
846 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(dsactx));
847 assert(pgpGetSigtag(dig) == RPMSIGTAG_DSA);
848 assert(sig != NULL);
849 
850  *t = '\0';
851  if (dig != NULL && dig->hdrsha1ctx == dsactx)
852  t = stpcpy(t, _("Header "));
853 
854  /* Identify the signature version. */
855  *t++ = 'V';
856  switch (sigp->version) {
857  case 3: *t++ = '3'; break;
858  case 4: *t++ = '4'; break;
859  }
860 
861  /* Identify the DSA/hash. */
862  { const char * hashname = rpmDigestName(dsactx);
863  t = stpcpy(t, " DSA");
864  if (strcmp(hashname, "UNKNOWN") && strcmp(hashname, "SHA1")) {
865  *t++ = '/';
866  t = stpcpy(t, hashname);
867  }
868  }
869  t = stpcpy(t, _(" signature: "));
870 
871  { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
872  DIGEST_CTX ctx = rpmDigestDup(dsactx);
873 
874  (void) rpmswEnter(op, 0);
875  if (sigp->hash != NULL)
876  xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
877 
878  if (sigp->version == (rpmuint8_t) 4) {
879  rpmuint32_t nb = (rpmuint32_t) sigp->hashlen;
880  rpmuint8_t trailer[6];
881  nb = (rpmuint32_t) htonl(nb);
882  trailer[0] = sigp->version;
883  trailer[1] = (rpmuint8_t)0xff;
884  memcpy(trailer+2, &nb, sizeof(nb));
885  xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
886  }
887  (void) rpmswExit(op, sigp->hashlen);
888  if (op != NULL) op->count--; /* XXX one too many */
889 
890  if (pgpImplSetDSA(ctx, dig, sigp)) {
891  res = RPMRC_FAIL;
892  goto exit;
893  }
894  }
895 
896  /* Retrieve the matching public key. */
897  res = pgpFindPubkey(dig);
898  if (res != RPMRC_OK)
899  goto exit;
900 
901  /* Verify the DSA signature. */
902  { rpmop op = pgpStatsAccumulator(dig, 11); /* RPMTS_OP_SIGNATURE */
903  (void) rpmswEnter(op, 0);
904  xx = pgpImplVerifyDSA(dig);
905  res = (xx ? RPMRC_OK : RPMRC_FAIL);
906  (void) rpmswExit(op, 0);
907  }
908 
909 exit:
910  /* Identify the pubkey fingerprint. */
911  t = stpcpy(t, rpmSigString(res));
912  if (sigp != NULL) {
913  t = stpcpy(t, ", key ID ");
914  (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
915  t += strlen(t);
916  }
917  return res;
918 }
919 
920 rpmRC
921 rpmVerifySignature(void * _dig, char * result)
922 {
923  pgpDig dig = _dig;
924  const void * sig = pgpGetSig(dig);
925  rpmuint32_t siglen = pgpGetSiglen(dig);
926  rpmSigTag sigtag = pgpGetSigtag(dig);
927  rpmRC res;
928 
929  if (dig == NULL || sig == NULL || siglen == 0) {
930  sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
931  return RPMRC_NOTFOUND;
932  }
933 
934  switch (sigtag) {
935  case RPMSIGTAG_SIZE:
936  res = verifySize(dig, result);
937  break;
938  case RPMSIGTAG_MD5:
939  res = verifyMD5(dig, result, dig->md5ctx);
940  break;
941  case RPMSIGTAG_SHA1:
942  res = verifySHA1(dig, result, dig->hdrsha1ctx);
943  break;
944  case RPMSIGTAG_RSA:
945  res = verifyRSA(dig, result, dig->hdrctx);
946  break;
947  case RPMSIGTAG_DSA:
948  res = verifyDSA(dig, result, dig->hdrsha1ctx);
949  break;
950  default:
951  sprintf(result, _("Signature: UNKNOWN (%u)\n"), (unsigned)sigtag);
952  res = RPMRC_NOTFOUND;
953  break;
954  }
955  return res;
956 }