rpm  5.4.10
package.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <netinet/in.h>
8 
9 #include <rpmio_internal.h>
10 #include <rpmcb.h> /* XXX fnpyKey */
11 
12 #define _RPMHKP_INTERNAL /* XXX internal prototypes. */
13 #include <rpmhkp.h>
14 
15 #include <rpmtag.h>
16 #include <rpmtypes.h>
17 #include <pkgio.h>
18 #include "signature.h" /* XXX rpmVerifySignature */
19 
20 #include "rpmts.h"
21 
22 #include "debug.h"
23 
24 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
25 
26 /*@access pgpDig @*/
27 /*@access pgpDigParams @*/
28 /*@access Header @*/ /* XXX compared with NULL */
29 /*@access FD_t @*/ /* XXX void * */
30 
31 /*@unchecked@*/ /*@only@*/ /*@null@*/
32 unsigned int * keyids = NULL;
33 
34 #ifndef DYING
35 /*@unchecked@*/
36 static unsigned int nkeyids_max = 256;
37 /*@unchecked@*/
38 static unsigned int nkeyids = 0;
39 /*@unchecked@*/
40 static unsigned int nextkeyid = 0;
41 
47 static int pgpStashKeyid(pgpDig dig)
48  /*@globals nextkeyid, nkeyids, keyids @*/
49  /*@modifies nextkeyid, nkeyids, keyids @*/
50 {
51  pgpDigParams sigp = pgpGetSignature(dig);
52  const void * sig = pgpGetSig(dig);
53  unsigned int keyid;
54  unsigned int i;
55 
56  if (sig == NULL || dig == NULL || sigp == NULL)
57  return 0;
58 
59  keyid = pgpGrab(sigp->signid+4, 4);
60  if (keyid == 0)
61  return 0;
62 
63  if (keyids != NULL)
64  for (i = 0; i < nkeyids; i++) {
65  if (keyid == keyids[i])
66  return 1;
67  }
68 
69  if (nkeyids < nkeyids_max) {
70  nkeyids++;
71  keyids = (unsigned int *) xrealloc(keyids, nkeyids * sizeof(*keyids));
72  }
73  if (keyids) /* XXX can't happen */
74  keyids[nextkeyid] = keyid;
75  nextkeyid++;
77 
78  return 0;
79 }
80 #endif
81 
82 /*@-mods@*/
83 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
84 {
85  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
86  HE_t she = (HE_t) memset(alloca(sizeof(*she)), 0, sizeof(*she));
87  pgpDig dig = rpmtsDig(ts);
88  char buf[8*BUFSIZ];
89  ssize_t count;
90  Header sigh = NULL;
91  rpmtsOpX opx;
92  rpmop op = NULL;
93  size_t nb;
94  unsigned ix;
95  Header h = NULL;
96  const char * msg = NULL;
98  rpmRC rc = RPMRC_FAIL; /* assume failure */
99  rpmop opsave = (rpmop) memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
100  int xx;
101 pgpPkt pp = (pgpPkt) alloca(sizeof(*pp));
102 
103  if (hdrp) *hdrp = NULL;
104 
105 assert(dig != NULL);
106  (void) fdSetDig(fd, dig);
107 
108  /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
109  (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));
110 
111  { const char item[] = "Lead";
112  msg = NULL;
113  rc = rpmpkgRead(item, fd, NULL, &msg);
114  switch (rc) {
115  default:
116  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
117  /*@fallthrough@*/
118  case RPMRC_NOTFOUND:
119  msg = _free(msg);
120  goto exit;
121  /*@notreached@*/ break;
122  case RPMRC_OK:
123  break;
124  }
125  msg = _free(msg);
126  }
127 
128  { const char item[] = "Signature";
129  msg = NULL;
130  rc = rpmpkgRead(item, fd, &sigh, &msg);
131  switch (rc) {
132  default:
133  rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item,
134  (msg && *msg ? msg : _("read failed\n")));
135  msg = _free(msg);
136  goto exit;
137  /*@notreached@*/ break;
138  case RPMRC_OK:
139  if (sigh == NULL) {
140  rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
141  rc = RPMRC_FAIL;
142  goto exit;
143  }
144  break;
145  }
146  msg = _free(msg);
147  }
148 
149 #define _chk(_mask) (she->tag == 0 && !(vsflags & (_mask)))
150 
151  /*
152  * Figger the most effective available signature.
153  * Prefer signatures over digests, then header-only over header+payload.
154  * DSA will be preferred over RSA if both exist because tested first.
155  * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
156  */
157  she->tag = (rpmTag)0;
158  opx = (rpmtsOpX)0;
159  vsflags = pgpDigVSFlags;
161  she->tag = (rpmTag)RPMSIGTAG_DSA;
162  } else
164  she->tag = (rpmTag)RPMSIGTAG_RSA;
165  } else
167  she->tag = (rpmTag)RPMSIGTAG_SHA1;
168  } else
171  {
172  she->tag = (rpmTag)RPMSIGTAG_MD5;
174  opx = RPMTS_OP_DIGEST;
175  }
176 
177  /* Read the metadata, computing digest(s) on the fly. */
178  h = NULL;
179  msg = NULL;
180 
181  /* XXX stats will include header i/o and setup overhead. */
182  /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
183  if (opx > 0) {
184  op = (rpmop) pgpStatsAccumulator(dig, opx);
185  (void) rpmswEnter(op, 0);
186  }
187 /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */
188  nb = fd->stats->ops[FDSTAT_READ].bytes;
189  { const char item[] = "Header";
190  msg = NULL;
191  rc = rpmpkgRead(item, fd, &h, &msg);
192  if (rc != RPMRC_OK) {
193  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
194  msg = _free(msg);
195  goto exit;
196  }
197  msg = _free(msg);
198  }
199  nb = fd->stats->ops[FDSTAT_READ].bytes - nb;
200 /*@=type@*/
201  if (opx > 0 && op != NULL) {
202  (void) rpmswExit(op, nb);
203  op = NULL;
204  }
205 
206  /* Any digests or signatures to check? */
207  if (she->tag == 0) {
208  rc = RPMRC_OK;
209  goto exit;
210  }
211 
212  dig->nbytes = 0;
213 
214  /* Fish out the autosign pubkey (if present). */
215  he->tag = RPMTAG_PUBKEYS;
216  xx = headerGet(h, he, 0);
217  if (xx && he->p.argv != NULL && he->c > 0)
218  switch (he->t) {
219  default:
220  break;
222  ix = he->c - 1; /* XXX FIXME: assumes last pubkey */
223  dig->pub = _free(dig->pub);
224  dig->publen = 0;
225  { rpmiob iob = rpmiobNew(0);
226  iob = rpmiobAppend(iob, he->p.argv[ix], 0);
227  xx = pgpArmorUnwrap(iob, (rpmuint8_t **)&dig->pub, &dig->publen);
228  iob = rpmiobFree(iob);
229  }
230  if (xx != PGPARMOR_PUBKEY) {
231  dig->pub = _free(dig->pub);
232  dig->publen = 0;
233  }
234  break;
235  }
236  he->p.ptr = _free(he->p.ptr);
237 
238  /* Retrieve the tag parameters from the signature header. */
239  xx = headerGet(sigh, she, 0);
240  if (she->p.ptr == NULL) {
241  rc = RPMRC_FAIL;
242  goto exit;
243  }
244 /*@-ownedtrans -noeffect@*/
245  xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
246 /*@=ownedtrans =noeffect@*/
247 
248  switch ((rpmSigTag)she->tag) {
249  default: /* XXX keep gcc quiet. */
250 assert(0);
251  /*@notreached@*/ break;
252  case RPMSIGTAG_RSA:
253  /* Parse the parameters from the OpenPGP packets that will be needed. */
254  xx = pgpPktLen(she->p.ui8p, she->c, pp);
255  xx = rpmhkpLoadSignature(NULL, dig, pp);
256  if (dig->signature.version != 3 && dig->signature.version != 4) {
258  _("skipping package %s with unverifiable V%u signature\n"),
259  fn, dig->signature.version);
260  rc = RPMRC_FAIL;
261  goto exit;
262  }
263  { void * uh = NULL;
264  rpmTagType uht;
265  rpmTagCount uhc;
266  unsigned char * hmagic = NULL;
267  size_t nmagic = 0;
268 
270  xx = headerGet(h, he, 0);
271  uht = he->t;
272  uh = he->p.ptr;
273  uhc = he->c;
274  if (!xx)
275  break;
276  (void) headerGetMagic(NULL, &hmagic, &nmagic);
277  op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
278  (void) rpmswEnter(op, 0);
279  dig->hdrctx = rpmDigestInit((pgpHashAlgo)dig->signature.hash_algo, RPMDIGEST_NONE);
280  if (hmagic && nmagic > 0) {
281  (void) rpmDigestUpdate(dig->hdrctx, hmagic, nmagic);
282  dig->nbytes += nmagic;
283  }
284  (void) rpmDigestUpdate(dig->hdrctx, uh, uhc);
285  dig->nbytes += uhc;
286  (void) rpmswExit(op, dig->nbytes);
287  op->count--; /* XXX one too many */
288  uh = _free(uh);
289  } break;
290  case RPMSIGTAG_DSA:
291  /* Parse the parameters from the OpenPGP packets that will be needed. */
292  xx = pgpPktLen(she->p.ui8p, she->c, pp);
293  xx = rpmhkpLoadSignature(NULL, dig, pp);
294  if (dig->signature.version != 3 && dig->signature.version != 4) {
296  _("skipping package %s with unverifiable V%u signature\n"),
297  fn, dig->signature.version);
298  rc = RPMRC_FAIL;
299  goto exit;
300  }
301  /*@fallthrough@*/
302  case RPMSIGTAG_SHA1:
303  { void * uh = NULL;
304  rpmTagType uht;
305  rpmTagCount uhc;
306  unsigned char * hmagic = NULL;
307  size_t nmagic = 0;
308 
310  xx = headerGet(h, he, 0);
311  uht = he->t;
312  uh = he->p.ptr;
313  uhc = he->c;
314  if (!xx)
315  break;
316  (void) headerGetMagic(NULL, &hmagic, &nmagic);
317  op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
318  (void) rpmswEnter(op, 0);
319  dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
320  if (hmagic && nmagic > 0) {
321  (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic);
322  dig->nbytes += nmagic;
323  }
324  (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
325  dig->nbytes += uhc;
326  (void) rpmswExit(op, dig->nbytes);
327  if ((rpmSigTag)she->tag == RPMSIGTAG_SHA1)
328  op->count--; /* XXX one too many */
329  uh = _free(uh);
330  } break;
331  case RPMSIGTAG_MD5:
332  /* Legacy signatures need the compressed payload in the digest too. */
333  op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
334  (void) rpmswEnter(op, 0);
335  while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
336  dig->nbytes += count;
337  (void) rpmswExit(op, dig->nbytes);
338  op->count--; /* XXX one too many */
339  dig->nbytes += nb; /* XXX include size of header blob. */
340  if (count < 0) {
341  rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
342  fn, Fstrerror(fd));
343  rc = RPMRC_FAIL;
344  goto exit;
345  }
346 
347  /* XXX Steal the digest-in-progress from the file handle. */
348  fdStealDigest(fd, dig);
349  break;
350  }
351 
354  buf[0] = '\0';
355  rc = rpmVerifySignature(dig, buf);
356  switch (rc) {
357  case RPMRC_OK: /* Signature is OK. */
358  rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf);
359  break;
360  case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */
361  case RPMRC_NOKEY: /* Public key is unavailable. */
362 #ifndef DYING
363  /* XXX Print NOKEY/NOTTRUSTED warning only once. */
364  { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
365  rpmlog(lvl, "%s: %s\n", fn, buf);
366  } break;
367  case RPMRC_NOTFOUND: /* Signature is unknown type. */
368  rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf);
369  break;
370 #else
371  case RPMRC_NOTFOUND: /* Signature is unknown type. */
372  case RPMRC_NOSIG: /* Signature is unavailable. */
373 #endif
374  default:
375  case RPMRC_FAIL: /* Signature does not verify. */
376  rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf);
377  break;
378  }
379 
380 exit:
381  if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
382 
383  /* Append (and remap) signature tags to the metadata. */
384  headerMergeLegacySigs(h, sigh);
385 
386  /* Bump reference count for return. */
387  *hdrp = headerLink(h);
388  }
389  (void)headerFree(h);
390  h = NULL;
391 
392  /* Accumulate time reading package header. */
393  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
394  fdstat_op(fd, FDSTAT_READ));
395  (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
396  opsave);
397 
398 #ifdef NOTYET
399  /* Return RPMRC_NOSIG for MANDATORY signature verification. */
400  { rpmSigTag sigtag = pgpGetSigtag(dig);
401  switch (sigtag) {
402  default:
403  rc = RPMRC_NOSIG;
404  /*@fallthrough@*/
405  case RPMSIGTAG_RSA:
406  case RPMSIGTAG_DSA:
407  break;
408  }
409  }
410 #endif
411 
412  rpmtsCleanDig(ts);
413  (void)headerFree(sigh);
414  sigh = NULL;
415  return rc;
416 }
417 /*@=mods@*/