rpm  4.5
rpmchecksig.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #include "rpmio_internal.h"
9 #include <rpmcli.h>
10 #define _RPMEVR_INTERNAL /* XXX RPMSENSE_KEYRING */
11 #include <rpmevr.h>
12 
13 #include "rpmdb.h"
14 
15 #include "rpmts.h"
16 
17 #include "rpmlead.h"
18 #include "signature.h"
19 #include "misc.h" /* XXX for makeTempFile() */
20 #include "debug.h"
21 
22 /*@access FD_t @*/ /* XXX stealing digests */
23 /*@access pgpDig @*/
24 /*@access pgpDigParams @*/
25 
26 /*@unchecked@*/
27 int _print_pkts = 0;
28 
31 /*@-boundsread@*/
32 static int manageFile(/*@out@*/ FD_t *fdp,
33  /*@null@*/ /*@out@*/ const char **fnp,
34  int flags, /*@unused@*/ int rc)
35  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
36  /*@modifies *fdp, *fnp, rpmGlobalMacroContext,
37  fileSystem, internalState @*/
38 {
39  const char *fn;
40  FD_t fd;
41 
42  if (fdp == NULL) /* programmer error */
43  return 1;
44 
45 /*@-boundswrite@*/
46  /* close and reset *fdp to NULL */
47  if (*fdp && (fnp == NULL || *fnp == NULL)) {
48  (void) Fclose(*fdp);
49  *fdp = NULL;
50  return 0;
51  }
52 
53  /* open a file and set *fdp */
54  if (*fdp == NULL && fnp != NULL && *fnp != NULL) {
55  fd = Fopen(*fnp, ((flags & O_WRONLY) ? "w" : "r"));
56  if (fd == NULL || Ferror(fd)) {
57  rpmError(RPMERR_OPEN, _("%s: open failed: %s\n"), *fnp,
58  Fstrerror(fd));
59  return 1;
60  }
61  *fdp = fd;
62  return 0;
63  }
64 
65  /* open a temp file */
66  if (*fdp == NULL && (fnp == NULL || *fnp == NULL)) {
67  fn = NULL;
68  if (makeTempFile(NULL, (fnp ? &fn : NULL), &fd)) {
69  rpmError(RPMERR_MAKETEMP, _("makeTempFile failed\n"));
70  return 1;
71  }
72  if (fnp != NULL)
73  *fnp = fn;
74  *fdp = fdLink(fd, "manageFile return");
75  fd = fdFree(fd, "manageFile return");
76  return 0;
77  }
78 /*@=boundswrite@*/
79 
80  /* no operation */
81  if (*fdp != NULL && fnp != NULL && *fnp != NULL)
82  return 0;
83 
84  /* XXX never reached */
85  return 1;
86 }
87 /*@=boundsread@*/
88 
92 /*@-boundsread@*/
93 static int copyFile(FD_t *sfdp, const char **sfnp,
94  FD_t *tfdp, const char **tfnp)
95  /*@globals rpmGlobalMacroContext, h_errno,
96  fileSystem, internalState @*/
97  /*@modifies *sfdp, *sfnp, *tfdp, *tfnp, rpmGlobalMacroContext,
98  fileSystem, internalState @*/
99 {
100  unsigned char buf[BUFSIZ];
101  ssize_t count;
102  int rc = 1;
103 
104  if (manageFile(sfdp, sfnp, O_RDONLY, 0))
105  goto exit;
106  if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC, 0))
107  goto exit;
108 
109  while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
110  {
111  if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) {
112  rpmError(RPMERR_FWRITE, _("%s: Fwrite failed: %s\n"), *tfnp,
113  Fstrerror(*tfdp));
114  goto exit;
115  }
116  }
117  if (count < 0) {
118  rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), *sfnp, Fstrerror(*sfdp));
119  goto exit;
120  }
121  if (Fflush(*tfdp) != 0) {
122  rpmError(RPMERR_FWRITE, _("%s: Fflush failed: %s\n"), *tfnp,
123  Fstrerror(*tfdp));
124  goto exit;
125  }
126 
127  rc = 0;
128 
129 exit:
130  if (*sfdp) (void) manageFile(sfdp, NULL, 0, rc);
131  if (*tfdp) (void) manageFile(tfdp, NULL, 0, rc);
132  return rc;
133 }
134 /*@=boundsread@*/
135 
143 static int getSignid(Header sig, int sigtag, unsigned char * signid)
144  /*@globals fileSystem, internalState @*/
145  /*@modifies *signid, fileSystem, internalState @*/
146 {
147  void * pkt = NULL;
148  int_32 pkttyp = 0;
149  int_32 pktlen = 0;
150  int rc = 1;
151 
152  if (headerGetEntry(sig, sigtag, &pkttyp, &pkt, &pktlen) && pkt != NULL) {
153  pgpDig dig = pgpNewDig();
154 
155  if (!pgpPrtPkts(pkt, pktlen, dig, 0)) {
156 /*@-bounds@*/
157  memcpy(signid, dig->signature.signid, sizeof(dig->signature.signid));
158 /*@=bounds@*/
159  rc = 0;
160  }
161 
162  dig = pgpFreeDig(dig);
163  }
164  pkt = headerFreeData(pkt, pkttyp);
165  return rc;
166 }
167 
175 static int rpmReSign(/*@unused@*/ rpmts ts,
176  QVA_t qva, const char ** argv)
177  /*@globals rpmGlobalMacroContext, h_errno,
178  fileSystem, internalState @*/
179  /*@modifies rpmGlobalMacroContext,
180  fileSystem, internalState @*/
181 {
182  FD_t fd = NULL;
183  FD_t ofd = NULL;
184  struct rpmlead lead, *l = &lead;
185  int_32 sigtag;
186  const char *rpm, *trpm;
187  const char *sigtarget = NULL;
188  char tmprpm[1024+1];
189  Header sigh = NULL;
190  const char * msg;
191  void * uh = NULL;
192  int_32 uht, uhc;
193  int res = EXIT_FAILURE;
194  int deleting = (qva->qva_mode == RPMSIGN_DEL_SIGNATURE);
195  rpmRC rc;
196  int xx;
197 
198  tmprpm[0] = '\0';
199  /*@-branchstate@*/
200 /*@-boundsread@*/
201  if (argv)
202  while ((rpm = *argv++) != NULL)
203 /*@=boundsread@*/
204  {
205 
206  fprintf(stdout, "%s:\n", rpm);
207 
208  if (manageFile(&fd, &rpm, O_RDONLY, 0))
209  goto exit;
210 
211 /*@-boundswrite@*/
212  memset(l, 0, sizeof(*l));
213 /*@=boundswrite@*/
214  rc = readLead(fd, l);
215  if (rc != RPMRC_OK) {
216  rpmError(RPMERR_READLEAD, _("%s: not an rpm package\n"), rpm);
217  goto exit;
218  }
219  switch (l->major) {
220  case 1:
221  rpmError(RPMERR_BADSIGTYPE, _("%s: Can't sign v1 packaging\n"), rpm);
222  goto exit;
223  /*@notreached@*/ /*@switchbreak@*/ break;
224  case 2:
225  rpmError(RPMERR_BADSIGTYPE, _("%s: Can't re-sign v2 packaging\n"), rpm);
226  goto exit;
227  /*@notreached@*/ /*@switchbreak@*/ break;
228  default:
229  /*@switchbreak@*/ break;
230  }
231 
232  msg = NULL;
233  rc = rpmReadSignature(fd, &sigh, l->signature_type, &msg);
234  switch (rc) {
235  default:
236  rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed: %s"), rpm,
237  (msg && *msg ? msg : "\n"));
238  msg = _free(msg);
239  goto exit;
240  /*@notreached@*/ /*@switchbreak@*/ break;
241  case RPMRC_OK:
242  if (sigh == NULL) {
243  rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), rpm);
244  goto exit;
245  }
246  /*@switchbreak@*/ break;
247  }
248  msg = _free(msg);
249 
250  /* Write the header and archive to a temp file */
251  /* ASSERT: ofd == NULL && sigtarget == NULL */
252  if (copyFile(&fd, &rpm, &ofd, &sigtarget))
253  goto exit;
254  /* Both fd and ofd are now closed. sigtarget contains tempfile name. */
255  /* ASSERT: fd == NULL && ofd == NULL */
256 
257  /* Dump the immutable region (if present). */
258  if (headerGetEntry(sigh, RPMTAG_HEADERSIGNATURES, &uht, &uh, &uhc)) {
259  HeaderIterator hi;
260  int_32 tag, type, count;
261  hPTR_t ptr;
262  Header oh;
263  Header nh;
264 
265  nh = headerNew();
266  if (nh == NULL) {
267  uh = headerFreeData(uh, uht);
268  goto exit;
269  }
270 
271  oh = headerCopyLoad(uh);
272  for (hi = headerInitIterator(oh);
273  headerNextIterator(hi, &tag, &type, &ptr, &count);
274  ptr = headerFreeData(ptr, type))
275  {
276  if (ptr)
277  xx = headerAddEntry(nh, tag, type, ptr, count);
278  }
279  hi = headerFreeIterator(hi);
280  oh = headerFree(oh);
281 
282  sigh = headerFree(sigh);
283  sigh = headerLink(nh);
284  nh = headerFree(nh);
285  }
286 
287  /* Eliminate broken digest values. */
292 
293  /* Toss and recalculate header+payload size and digests. */
294  xx = headerRemoveEntry(sigh, RPMSIGTAG_SIZE);
295  xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase);
296  xx = headerRemoveEntry(sigh, RPMSIGTAG_MD5);
297  xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_MD5, qva->passPhrase);
298  xx = headerRemoveEntry(sigh, RPMSIGTAG_SHA1);
299  xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SHA1, qva->passPhrase);
300 
301  if (deleting) { /* Nuke all the signature tags. */
302  xx = headerRemoveEntry(sigh, RPMSIGTAG_GPG);
303  xx = headerRemoveEntry(sigh, RPMSIGTAG_DSA);
304  xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP5);
305  xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP);
306  xx = headerRemoveEntry(sigh, RPMSIGTAG_RSA);
307  } else /* If gpg/pgp is configured, replace the signature. */
308  if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
309  unsigned char oldsignid[8], newsignid[8];
310 
311  /* Grab the old signature fingerprint (if any) */
312  memset(oldsignid, 0, sizeof(oldsignid));
313  xx = getSignid(sigh, sigtag, oldsignid);
314 
315  switch (sigtag) {
316  case RPMSIGTAG_DSA:
317  xx = headerRemoveEntry(sigh, RPMSIGTAG_GPG);
318  /*@switchbreak@*/ break;
319  case RPMSIGTAG_RSA:
320  xx = headerRemoveEntry(sigh, RPMSIGTAG_PGP);
321  /*@switchbreak@*/ break;
322  case RPMSIGTAG_GPG:
323  xx = headerRemoveEntry(sigh, RPMSIGTAG_DSA);
324  /*@fallthrough@*/
325  case RPMSIGTAG_PGP5:
326  case RPMSIGTAG_PGP:
327  xx = headerRemoveEntry(sigh, RPMSIGTAG_RSA);
328  /*@switchbreak@*/ break;
329  }
330 
331  xx = headerRemoveEntry(sigh, sigtag);
332  xx = rpmAddSignature(sigh, sigtarget, sigtag, qva->passPhrase);
333 
334  /* If package was previously signed, check for same signer. */
335  memset(newsignid, 0, sizeof(newsignid));
336  if (memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
337 
338  /* Grab the new signature fingerprint */
339  xx = getSignid(sigh, sigtag, newsignid);
340 
341  /* If same signer, skip resigning the package. */
342  if (!memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
343 
345  _("%s: was already signed by key ID %s, skipping\n"),
346  rpm, pgpHexStr(newsignid+4, sizeof(newsignid)-4));
347 
348  /* Clean up intermediate target */
349  xx = unlink(sigtarget);
350  sigtarget = _free(sigtarget);
351  continue;
352  }
353  }
354  }
355 
356  /* Reallocate the signature into one contiguous region. */
358  if (sigh == NULL) /* XXX can't happen */
359  goto exit;
360 
361  /* Write the lead/signature of the output rpm */
362 /*@-boundswrite@*/
363  strcpy(tmprpm, rpm);
364  strcat(tmprpm, ".XXXXXX");
365 /*@=boundswrite@*/
366  (void) mktemp(tmprpm);
367  trpm = tmprpm;
368 
369  if (manageFile(&ofd, &trpm, O_WRONLY|O_CREAT|O_TRUNC, 0))
370  goto exit;
371 
373  rc = writeLead(ofd, l);
374  if (rc != RPMRC_OK) {
375  rpmError(RPMERR_WRITELEAD, _("%s: writeLead failed: %s\n"), trpm,
376  Fstrerror(ofd));
377  goto exit;
378  }
379 
380  if (rpmWriteSignature(ofd, sigh)) {
381  rpmError(RPMERR_SIGGEN, _("%s: rpmWriteSignature failed: %s\n"), trpm,
382  Fstrerror(ofd));
383  goto exit;
384  }
385 
386  /* Append the header and archive from the temp file */
387  /* ASSERT: fd == NULL && ofd != NULL */
388  if (copyFile(&fd, &sigtarget, &ofd, &trpm))
389  goto exit;
390  /* Both fd and ofd are now closed. */
391  /* ASSERT: fd == NULL && ofd == NULL */
392 
393  /* Move final target into place. */
394  xx = unlink(rpm);
395  xx = rename(trpm, rpm);
396  tmprpm[0] = '\0';
397 
398  /* Clean up intermediate target */
399  xx = unlink(sigtarget);
400  sigtarget = _free(sigtarget);
401  }
402  /*@=branchstate@*/
403 
404  res = 0;
405 
406 exit:
407  if (fd) (void) manageFile(&fd, NULL, 0, res);
408  if (ofd) (void) manageFile(&ofd, NULL, 0, res);
409 
410  sigh = rpmFreeSignature(sigh);
411 
412  if (sigtarget) {
413  xx = unlink(sigtarget);
414  sigtarget = _free(sigtarget);
415  }
416  if (tmprpm[0] != '\0') {
417  xx = unlink(tmprpm);
418  tmprpm[0] = '\0';
419  }
420 
421  return res;
422 }
423 
424 rpmRC rpmcliImportPubkey(const rpmts ts, const unsigned char * pkt, ssize_t pktlen)
425 {
426  static unsigned char zeros[] =
427  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
428  const char * afmt = "%{pubkeys:armor}";
429  const char * group = "Public Keys";
430  const char * license = "pubkey";
431  const char * buildhost = "localhost";
432  int_32 pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
433  int_32 zero = 0;
434  pgpDig dig = NULL;
435  pgpDigParams pubp = NULL;
436  const char * d = NULL;
437  const char * enc = NULL;
438  const char * n = NULL;
439  const char * u = NULL;
440  const char * v = NULL;
441  const char * r = NULL;
442  const char * evr = NULL;
443  Header h = NULL;
444  rpmRC rc = RPMRC_FAIL; /* assume failure */
445  char * t;
446  int xx;
447 
448  if (pkt == NULL || pktlen <= 0)
449  return RPMRC_FAIL;
450  if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
451  return RPMRC_FAIL;
452 
453  if ((enc = b64encode(pkt, pktlen)) == NULL)
454  goto exit;
455 
456  dig = pgpNewDig();
457 
458  /* Build header elements. */
459  (void) pgpPrtPkts(pkt, pktlen, dig, 0);
460  pubp = &dig->pubkey;
461 
462  if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
463  || !memcmp(pubp->time, zeros, sizeof(pubp->time))
464  || pubp->userid == NULL)
465  goto exit;
466 
467 /*@-boundswrite@*/
468  v = t = xmalloc(16+1);
469  t = stpcpy(t, pgpHexStr(pubp->signid, sizeof(pubp->signid)));
470 
471  r = t = xmalloc(8+1);
472  t = stpcpy(t, pgpHexStr(pubp->time, sizeof(pubp->time)));
473 
474  n = t = xmalloc(sizeof("gpg()")+8);
475  t = stpcpy( stpcpy( stpcpy(t, "gpg("), v+8), ")");
476 
477  /*@-nullpass@*/ /* FIX: pubp->userid may be NULL */
478  u = t = xmalloc(sizeof("gpg()")+strlen(pubp->userid));
479  t = stpcpy( stpcpy( stpcpy(t, "gpg("), pubp->userid), ")");
480  /*@=nullpass@*/
481 
482  evr = t = xmalloc(sizeof("4X:-")+strlen(v)+strlen(r));
483  t = stpcpy(t, (pubp->version == 4 ? "4:" : "3:"));
484  t = stpcpy( stpcpy( stpcpy(t, v), "-"), r);
485 /*@=boundswrite@*/
486 
487  /* Check for pre-existing header. */
488 
489  /* Build pubkey header. */
490  h = headerNew();
491 
493  RPM_STRING_ARRAY_TYPE, &enc, 1);
494 
495  d = headerSprintf(h, afmt, rpmTagTable, rpmHeaderFormats, NULL);
496  if (d == NULL)
497  goto exit;
498 
499  xx = headerAddEntry(h, RPMTAG_NAME, RPM_STRING_TYPE, "gpg-pubkey", 1);
503  xx = headerAddEntry(h, RPMTAG_GROUP, RPM_STRING_TYPE, group, 1);
504  xx = headerAddEntry(h, RPMTAG_LICENSE, RPM_STRING_TYPE, license, 1);
506 
507  xx = headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &zero, 1);
508 
510  RPM_STRING_ARRAY_TYPE, &u, 1);
512  RPM_STRING_ARRAY_TYPE, &evr, 1);
514  RPM_INT32_TYPE, &pflags, 1);
515 
517  RPM_STRING_ARRAY_TYPE, &n, 1);
519  RPM_STRING_ARRAY_TYPE, &evr, 1);
521  RPM_INT32_TYPE, &pflags, 1);
522 
524 
525  /* XXX W2DO: tag value inheirited from parent? */
526  xx = headerAddEntry(h, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildhost, 1);
527  { int_32 tid = rpmtsGetTid(ts);
529  /* XXX W2DO: tag value inheirited from parent? */
531  }
532 
533 #ifdef NOTYET
534  /* XXX W2DO: tag value inheirited from parent? */
536 #endif
537 
538  /* Add header to database. */
539  xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL, NULL);
540  if (xx != 0)
541  goto exit;
542  rc = RPMRC_OK;
543 
544 exit:
545  /* Clean up. */
546  h = headerFree(h);
547  dig = pgpFreeDig(dig);
548  n = _free(n);
549  u = _free(u);
550  v = _free(v);
551  r = _free(r);
552  evr = _free(evr);
553  enc = _free(enc);
554  d = _free(d);
555 
556  return rc;
557 }
558 
567 static int rpmcliImportPubkeys(const rpmts ts,
568  /*@unused@*/ QVA_t qva,
569  /*@null@*/ const char ** argv)
570  /*@globals RPMVERSION, rpmGlobalMacroContext, h_errno,
571  fileSystem, internalState @*/
572  /*@modifies ts, rpmGlobalMacroContext,
573  fileSystem, internalState @*/
574 {
575  const char * fn;
576  const unsigned char * pkt = NULL;
577  ssize_t pktlen = 0;
578  char * t = NULL;
579  int res = 0;
580  rpmRC rpmrc;
581  int rc;
582 
583  if (argv == NULL) return res;
584 
585  /*@-branchstate@*/
586 /*@-boundsread@*/
587  while ((fn = *argv++) != NULL) {
588 /*@=boundsread@*/
589 
590  rpmtsClean(ts);
591  pkt = _free(pkt);
592  t = _free(t);
593 
594  /* If arg looks like a keyid, then attempt keyserver retrieve. */
595  if (fn[0] == '0' && fn[1] == 'x') {
596  const char * s;
597  int i;
598  for (i = 0, s = fn+2; *s && isxdigit(*s); s++, i++)
599  {};
600  if (i == 8 || i == 16) {
601  t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
602  if (t && *t != '%')
603  fn = t;
604  }
605  }
606 
607  /* Read pgp packet. */
608  if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
609  rpmError(RPMERR_IMPORT, _("%s: import read failed(%d).\n"), fn, rc);
610  res++;
611  continue;
612  }
613  if (rc != PGPARMOR_PUBKEY) {
614  rpmError(RPMERR_IMPORT, _("%s: not an armored public key.\n"), fn);
615  res++;
616  continue;
617  }
618 
619  /* Import pubkey packet(s). */
620  if ((rpmrc = rpmcliImportPubkey(ts, pkt, pktlen)) != RPMRC_OK) {
621  rpmError(RPMERR_IMPORT, _("%s: import failed.\n"), fn);
622  res++;
623  continue;
624  }
625 
626  }
627  /*@=branchstate@*/
628 
629 rpmtsClean(ts);
630  pkt = _free(pkt);
631  t = _free(t);
632  return res;
633 }
634 
635 /*@unchecked@*/
636 static unsigned char header_magic[8] = {
637  0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
638 };
639 
643 static int readFile(FD_t fd, const char * fn, pgpDig dig)
644  /*@globals fileSystem, internalState @*/
645  /*@modifies fd, *dig, fileSystem, internalState @*/
646 {
647  unsigned char buf[4*BUFSIZ];
648  ssize_t count;
649  int rc = 1;
650  int i;
651 
652  dig->nbytes = 0;
653 
654  /* Read the header from the package. */
656  if (h == NULL) {
657  rpmError(RPMERR_FREAD, _("%s: headerRead failed\n"), fn);
658  goto exit;
659  }
660 
662 
664  void * uh;
665  int_32 uht, uhc;
666 
667  if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)
668  || uh == NULL)
669  {
670  h = headerFree(h);
671  rpmError(RPMERR_FREAD, _("%s: headerGetEntry failed\n"), fn);
672  goto exit;
673  }
675  (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
676  (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
678  (void) rpmDigestUpdate(dig->hdrmd5ctx, header_magic, sizeof(header_magic));
679  (void) rpmDigestUpdate(dig->hdrmd5ctx, uh, uhc);
680  uh = headerFreeData(uh, uht);
681  }
682  h = headerFree(h);
683  }
684 
685  /* Read the payload from the package. */
686  while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
687  dig->nbytes += count;
688  if (count < 0) {
689  rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
690  goto exit;
691  }
692 
693  /* XXX Steal the digest-in-progress from the file handle. */
694  for (i = fd->ndigests - 1; i >= 0; i--) {
695  FDDIGEST_t fddig = fd->digests + i;
696  if (fddig->hashctx != NULL)
697  switch (fddig->hashalgo) {
698  case PGPHASHALGO_MD5:
699 assert(dig->md5ctx == NULL);
700  dig->md5ctx = fddig->hashctx;
701  fddig->hashctx = NULL;
702  /*@switchbreak@*/ break;
703  case PGPHASHALGO_SHA1:
705 #if HAVE_BEECRYPT_API_H
706  case PGPHASHALGO_SHA256:
707  case PGPHASHALGO_SHA384:
708  case PGPHASHALGO_SHA512:
709 #endif
710 assert(dig->sha1ctx == NULL);
711  dig->sha1ctx = fddig->hashctx;
712  fddig->hashctx = NULL;
713  /*@switchbreak@*/ break;
714  default:
715  /*@switchbreak@*/ break;
716  }
717  }
718 
719  rc = 0;
720 
721 exit:
722  return rc;
723 }
724 
726  const char * fn)
727 {
728  int res2, res3;
729  struct rpmlead lead, *l = &lead;
730  char result[1024];
731  char buf[8192], * b;
732  char missingKeys[7164], * m;
733  char untrustedKeys[7164], * u;
734  int_32 sigtag;
735  int_32 sigtype;
736  const void * sig;
737  pgpDig dig;
738  pgpDigParams sigp;
739  int_32 siglen;
740  Header sigh = NULL;
741  HeaderIterator hi;
742  const char * msg;
743  int res = 0;
744  int xx;
745  rpmRC rc;
746  int nodigests = !(qva->qva_flags & VERIFY_DIGEST);
747  int nosignatures = !(qva->qva_flags & VERIFY_SIGNATURE);
748 
749  {
750 /*@-boundswrite@*/
751  memset(l, 0, sizeof(*l));
752 /*@=boundswrite@*/
753  rc = readLead(fd, l);
754  if (rc != RPMRC_OK) {
755  rpmError(RPMERR_READLEAD, _("%s: not an rpm package\n"), fn);
756  res++;
757  goto exit;
758  }
759  switch (l->major) {
760  case 1:
761  rpmError(RPMERR_BADSIGTYPE, _("%s: No signature available (v1.0 RPM)\n"), fn);
762  res++;
763  goto exit;
764  /*@notreached@*/ /*@switchbreak@*/ break;
765  default:
766  /*@switchbreak@*/ break;
767  }
768 
769  msg = NULL;
770  rc = rpmReadSignature(fd, &sigh, l->signature_type, &msg);
771  switch (rc) {
772  default:
773  rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed: %s"), fn,
774  (msg && *msg ? msg : "\n"));
775  msg = _free(msg);
776  res++;
777  goto exit;
778  /*@notreached@*/ /*@switchbreak@*/ break;
779  case RPMRC_OK:
780  if (sigh == NULL) {
781  rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), fn);
782  res++;
783  goto exit;
784  }
785  /*@switchbreak@*/ break;
786  }
787  msg = _free(msg);
788 
789  /* Grab a hint of what needs doing to avoid duplication. */
790  sigtag = 0;
791  if (sigtag == 0 && !nosignatures) {
792  if (headerIsEntry(sigh, RPMSIGTAG_DSA))
793  sigtag = RPMSIGTAG_DSA;
794  else if (headerIsEntry(sigh, RPMSIGTAG_RSA))
795  sigtag = RPMSIGTAG_RSA;
796  else if (headerIsEntry(sigh, RPMSIGTAG_GPG))
797  sigtag = RPMSIGTAG_GPG;
798  else if (headerIsEntry(sigh, RPMSIGTAG_PGP))
799  sigtag = RPMSIGTAG_PGP;
800  }
801  if (sigtag == 0 && !nodigests) {
802  if (headerIsEntry(sigh, RPMSIGTAG_MD5))
803  sigtag = RPMSIGTAG_MD5;
804  else if (headerIsEntry(sigh, RPMSIGTAG_SHA1))
805  sigtag = RPMSIGTAG_SHA1; /* XXX never happens */
806  }
807 
808  dig = rpmtsDig(ts);
809 assert(dig != NULL);
810  sigp = rpmtsSignature(ts);
811 
812  /* XXX RSA needs the hash_algo, so decode early. */
813  if (sigtag == RPMSIGTAG_RSA || sigtag == RPMSIGTAG_PGP) {
814  xx = headerGetEntry(sigh, sigtag, &sigtype, (void **)&sig, &siglen);
815  xx = pgpPrtPkts(sig, siglen, dig, 0);
816  sig = headerFreeData(sig, sigtype);
817  /* XXX assume same hash_algo in header-only and header+payload */
818  if ((headerIsEntry(sigh, RPMSIGTAG_PGP)
819  || headerIsEntry(sigh, RPMSIGTAG_PGP5))
821  fdInitDigest(fd, dig->signature.hash_algo, 0);
822  }
823 
824  if (headerIsEntry(sigh, RPMSIGTAG_PGP)
825  || headerIsEntry(sigh, RPMSIGTAG_PGP5)
826  || headerIsEntry(sigh, RPMSIGTAG_MD5))
828  if (headerIsEntry(sigh, RPMSIGTAG_GPG))
830 
831  /* Read the file, generating digest(s) on the fly. */
832  if (dig == NULL || sigp == NULL || readFile(fd, fn, dig)) {
833  res++;
834  goto exit;
835  }
836 
837  res2 = 0;
838  b = buf; *b = '\0';
839  m = missingKeys; *m = '\0';
840  u = untrustedKeys; *u = '\0';
841  sprintf(b, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
842  b += strlen(b);
843 
844  for (hi = headerInitIterator(sigh);
845  headerNextIterator(hi, &sigtag, &sigtype, &sig, &siglen) != 0;
846  (void) rpmtsSetSig(ts, sigtag, sigtype, NULL, siglen))
847  {
848 
849  if (sig == NULL) /* XXX can't happen */
850  continue;
851 
852  (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
853 
854  /* Clean up parameters from previous sigtag. */
855  pgpCleanDig(dig);
856 
857  switch (sigtag) {
858  case RPMSIGTAG_RSA:
859  case RPMSIGTAG_DSA:
860  case RPMSIGTAG_GPG:
861  case RPMSIGTAG_PGP5: /* XXX legacy */
862  case RPMSIGTAG_PGP:
863  if (nosignatures)
864  continue;
865  xx = pgpPrtPkts(sig, siglen, dig,
866  (_print_pkts & rpmIsDebug()));
867 
868  if (sigp->version != 3 && sigp->version != 4) {
870  _("skipping package %s with unverifiable V%u signature\n"),
871  fn, sigp->version);
872  res++;
873  goto exit;
874  }
875  /*@switchbreak@*/ break;
876  case RPMSIGTAG_SHA1:
877  if (nodigests)
878  continue;
879  /* XXX Don't bother with header sha1 if header dsa. */
880  if (!nosignatures && sigtag == RPMSIGTAG_DSA)
881  continue;
882  /*@switchbreak@*/ break;
883  case RPMSIGTAG_LEMD5_2:
884  case RPMSIGTAG_LEMD5_1:
885  case RPMSIGTAG_MD5:
886  if (nodigests)
887  continue;
888  /*
889  * Don't bother with md5 if pgp, as RSA/MD5 is more reliable
890  * than the -- now unsupported -- legacy md5 breakage.
891  */
892  if (!nosignatures && sigtag == RPMSIGTAG_PGP)
893  continue;
894  /*@switchbreak@*/ break;
895  default:
896  continue;
897  /*@notreached@*/ /*@switchbreak@*/ break;
898  }
899 
900  res3 = rpmVerifySignature(ts, result);
901 
902 /*@-bounds@*/
903  if (res3) {
904  if (rpmIsVerbose()) {
905  b = stpcpy(b, " ");
906  b = stpcpy(b, result);
907  res2 = 1;
908  } else {
909  char *tempKey;
910  switch (sigtag) {
911  case RPMSIGTAG_SIZE:
912  b = stpcpy(b, "SIZE ");
913  res2 = 1;
914  /*@switchbreak@*/ break;
915  case RPMSIGTAG_SHA1:
916  b = stpcpy(b, "SHA1 ");
917  res2 = 1;
918  /*@switchbreak@*/ break;
919  case RPMSIGTAG_LEMD5_2:
920  case RPMSIGTAG_LEMD5_1:
921  case RPMSIGTAG_MD5:
922  b = stpcpy(b, "MD5 ");
923  res2 = 1;
924  /*@switchbreak@*/ break;
925  case RPMSIGTAG_RSA:
926  b = stpcpy(b, "RSA ");
927  res2 = 1;
928  /*@switchbreak@*/ break;
929  case RPMSIGTAG_PGP5: /* XXX legacy */
930  case RPMSIGTAG_PGP:
931  switch (res3) {
932  case RPMRC_NOKEY:
933  res2 = 1;
934  /*@fallthrough@*/
935  case RPMRC_NOTTRUSTED:
936  { int offset = 6;
937  b = stpcpy(b, "(MD5) (PGP) ");
938  tempKey = strstr(result, "ey ID");
939  if (tempKey == NULL) {
940  tempKey = strstr(result, "keyid:");
941  offset = 9;
942  }
943  if (tempKey) {
944  if (res3 == RPMRC_NOKEY) {
945  m = stpcpy(m, " PGP#");
946  m = stpncpy(m, tempKey + offset, 8);
947  *m = '\0';
948  } else {
949  u = stpcpy(u, " PGP#");
950  u = stpncpy(u, tempKey + offset, 8);
951  *u = '\0';
952  }
953  }
954  } /*@innerbreak@*/ break;
955  default:
956  b = stpcpy(b, "MD5 PGP ");
957  res2 = 1;
958  /*@innerbreak@*/ break;
959  }
960  /*@switchbreak@*/ break;
961  case RPMSIGTAG_DSA:
962  b = stpcpy(b, "(SHA1) DSA ");
963  res2 = 1;
964  /*@switchbreak@*/ break;
965  case RPMSIGTAG_GPG:
966  /* Do not consider this a failure */
967  switch (res3) {
968  case RPMRC_NOKEY:
969  b = stpcpy(b, "(GPG) ");
970  m = stpcpy(m, " GPG#");
971  tempKey = strstr(result, "ey ID");
972  if (tempKey) {
973  m = stpncpy(m, tempKey+6, 8);
974  *m = '\0';
975  }
976  res2 = 1;
977  /*@innerbreak@*/ break;
978  default:
979  b = stpcpy(b, "GPG ");
980  res2 = 1;
981  /*@innerbreak@*/ break;
982  }
983  /*@switchbreak@*/ break;
984  default:
985  b = stpcpy(b, "?UnknownSignatureType? ");
986  res2 = 1;
987  /*@switchbreak@*/ break;
988  }
989  }
990  } else {
991  if (rpmIsVerbose()) {
992  b = stpcpy(b, " ");
993  b = stpcpy(b, result);
994  } else {
995  switch (sigtag) {
996  case RPMSIGTAG_SIZE:
997  b = stpcpy(b, "size ");
998  /*@switchbreak@*/ break;
999  case RPMSIGTAG_SHA1:
1000  b = stpcpy(b, "sha1 ");
1001  /*@switchbreak@*/ break;
1002  case RPMSIGTAG_LEMD5_2:
1003  case RPMSIGTAG_LEMD5_1:
1004  case RPMSIGTAG_MD5:
1005  b = stpcpy(b, "md5 ");
1006  /*@switchbreak@*/ break;
1007  case RPMSIGTAG_RSA:
1008  b = stpcpy(b, "rsa ");
1009  /*@switchbreak@*/ break;
1010  case RPMSIGTAG_PGP5: /* XXX legacy */
1011  case RPMSIGTAG_PGP:
1012  b = stpcpy(b, "(md5) pgp ");
1013  /*@switchbreak@*/ break;
1014  case RPMSIGTAG_DSA:
1015  b = stpcpy(b, "(sha1) dsa ");
1016  /*@switchbreak@*/ break;
1017  case RPMSIGTAG_GPG:
1018  b = stpcpy(b, "gpg ");
1019  /*@switchbreak@*/ break;
1020  default:
1021  b = stpcpy(b, "??? ");
1022  /*@switchbreak@*/ break;
1023  }
1024  }
1025  }
1026 /*@=bounds@*/
1027  }
1028  hi = headerFreeIterator(hi);
1029 
1030  res += res2;
1031 
1032  if (res2) {
1033  if (rpmIsVerbose()) {
1034  rpmError(RPMERR_SIGVFY, "%s", buf);
1035  } else {
1036  rpmError(RPMERR_SIGVFY, "%s%s%s%s%s%s%s%s\n", buf,
1037  _("NOT OK"),
1038  (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
1039  missingKeys,
1040  (missingKeys[0] != '\0') ? _(") ") : "",
1041  (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
1042  untrustedKeys,
1043  (untrustedKeys[0] != '\0') ? _(")") : "");
1044 
1045  }
1046  } else {
1047  if (rpmIsVerbose()) {
1048  rpmError(RPMERR_SIGVFY, "%s", buf);
1049  } else {
1050  rpmError(RPMERR_SIGVFY, "%s%s%s%s%s%s%s%s\n", buf,
1051  _("OK"),
1052  (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
1053  missingKeys,
1054  (missingKeys[0] != '\0') ? _(") ") : "",
1055  (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
1056  untrustedKeys,
1057  (untrustedKeys[0] != '\0') ? _(")") : "");
1058  }
1059  }
1060 
1061  }
1062 
1063 exit:
1064  sigh = rpmFreeSignature(sigh);
1065  rpmtsCleanDig(ts);
1066  return res;
1067 }
1068 
1069 int rpmcliSign(rpmts ts, QVA_t qva, const char ** argv)
1070 {
1071  const char * arg;
1072  int res = 0;
1073  int xx;
1074 
1075  if (argv == NULL) return res;
1076 
1077  switch (qva->qva_mode) {
1078  case RPMSIGN_CHK_SIGNATURE:
1079  break;
1080  case RPMSIGN_IMPORT_PUBKEY:
1081  return rpmcliImportPubkeys(ts, qva, argv);
1082  /*@notreached@*/ break;
1083  case RPMSIGN_NEW_SIGNATURE:
1084  case RPMSIGN_ADD_SIGNATURE:
1085  case RPMSIGN_DEL_SIGNATURE:
1086  return rpmReSign(ts, qva, argv);
1087  /*@notreached@*/ break;
1088  case RPMSIGN_NONE:
1089  default:
1090  return -1;
1091  /*@notreached@*/ break;
1092  }
1093 
1094  while ((arg = *argv++) != NULL) {
1095  FD_t fd;
1096 
1097  if ((fd = Fopen(arg, "r")) == NULL
1098  || Ferror(fd)
1099  || rpmVerifySignatures(qva, ts, fd, arg))
1100  res++;
1101 
1102  if (fd != NULL) xx = Fclose(fd);
1103  }
1104 
1105  return res;
1106 }