rpm  5.4.15
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 static int hBlobDigest(Header h, pgpDig dig, pgpHashAlgo hash_algo,
83  DIGEST_CTX * ctxp)
84 {
85  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
86  rpmop op = NULL;
87  unsigned char * hmagic = NULL;
88  size_t nmagic = 0;
89  int xx;
90 
92  xx = headerGet(h, he, 0);
93  if (!xx)
94  goto exit;
95  (void) headerGetMagic(NULL, &hmagic, &nmagic);
96  op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
97  (void) rpmswEnter(op, 0);
98  *ctxp = rpmDigestInit(hash_algo, RPMDIGEST_NONE);
99  if (hmagic && nmagic > 0) {
100  (void) rpmDigestUpdate(*ctxp, hmagic, nmagic);
101  dig->nbytes += nmagic;
102  }
103  (void) rpmDigestUpdate(*ctxp, he->p.ptr, he->c);
104  dig->nbytes += he->c;
105  (void) rpmswExit(op, dig->nbytes);
106  op->count--; /* XXX one too many */
107 
108 exit:
109  he->p.ptr = _free(he->p.ptr);
110  return xx;
111 }
112 
113 /*@-mods@*/
114 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
115 {
116  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
117  HE_t she = (HE_t) memset(alloca(sizeof(*she)), 0, sizeof(*she));
118  pgpDig dig = rpmtsDig(ts);
119  char buf[8*BUFSIZ];
120  ssize_t count;
121  Header sigh = NULL;
122  rpmtsOpX opx;
123  rpmop op = NULL;
124  size_t nb;
125  unsigned ix;
126  Header h = NULL;
127  const char * msg = NULL;
129  rpmRC rc = RPMRC_FAIL; /* assume failure */
130  rpmop opsave = (rpmop) memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
131  int xx;
132 pgpPkt pp = (pgpPkt) alloca(sizeof(*pp));
133 
134  if (hdrp) *hdrp = NULL;
135 
136 assert(dig != NULL);
137  (void) fdSetDig(fd, dig);
138 
139  /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
140  (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));
141 
142  { const char item[] = "Lead";
143  msg = NULL;
144  rc = rpmpkgRead(item, fd, NULL, &msg);
145  switch (rc) {
146  default:
147  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
148  /*@fallthrough@*/
149  case RPMRC_NOTFOUND:
150  msg = _free(msg);
151  goto exit;
152  /*@notreached@*/ break;
153  case RPMRC_OK:
154  break;
155  }
156  msg = _free(msg);
157  }
158 
159  { const char item[] = "Signature";
160  msg = NULL;
161  rc = rpmpkgRead(item, fd, &sigh, &msg);
162  switch (rc) {
163  default:
164  rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item,
165  (msg && *msg ? msg : _("read failed\n")));
166  msg = _free(msg);
167  goto exit;
168  /*@notreached@*/ break;
169  case RPMRC_OK:
170  if (sigh == NULL) {
171  rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
172  rc = RPMRC_FAIL;
173  goto exit;
174  }
175  break;
176  }
177  msg = _free(msg);
178  }
179 
180 #define _chk(_mask) (she->tag == 0 && !(vsflags & (_mask)))
181 
182  /*
183  * Figger the most effective available signature.
184  * Prefer signatures over digests, then header-only over header+payload.
185  * DSA will be preferred over RSA if both exist because tested first.
186  * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
187  */
188  she->tag = (rpmTag)0;
189  opx = (rpmtsOpX)0;
190  vsflags = pgpDigVSFlags;
192  she->tag = (rpmTag)RPMSIGTAG_ECDSA;
193  } else
195  she->tag = (rpmTag)RPMSIGTAG_DSA;
196  } else
198  she->tag = (rpmTag)RPMSIGTAG_RSA;
199  } else
201  she->tag = (rpmTag)RPMSIGTAG_SHA1;
202  } else
205  {
206  she->tag = (rpmTag)RPMSIGTAG_MD5;
208  opx = RPMTS_OP_DIGEST;
209  }
210 
211  /* Read the metadata, computing digest(s) on the fly. */
212  h = NULL;
213  msg = NULL;
214 
215  /* XXX stats will include header i/o and setup overhead. */
216  /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
217  if (opx > 0) {
218  op = (rpmop) pgpStatsAccumulator(dig, opx);
219  (void) rpmswEnter(op, 0);
220  }
221 /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */
222  nb = fd->stats->ops[FDSTAT_READ].bytes;
223  { const char item[] = "Header";
224  msg = NULL;
225  rc = rpmpkgRead(item, fd, &h, &msg);
226  if (rc != RPMRC_OK) {
227  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
228  msg = _free(msg);
229  goto exit;
230  }
231  msg = _free(msg);
232  }
233  nb = fd->stats->ops[FDSTAT_READ].bytes - nb;
234 /*@=type@*/
235  if (opx > 0 && op != NULL) {
236  (void) rpmswExit(op, nb);
237  op = NULL;
238  }
239 
240  /* Any digests or signatures to check? */
241  if (she->tag == 0) {
242  rc = RPMRC_OK;
243  goto exit;
244  }
245 
246  dig->nbytes = 0;
247 
248  /* Fish out the autosign pubkey (if present). */
249  he->tag = RPMTAG_PUBKEYS;
250  xx = headerGet(h, he, 0);
251  if (xx && he->p.argv != NULL && he->c > 0)
252  switch (he->t) {
253  default:
254  break;
256  ix = he->c - 1; /* XXX FIXME: assumes last pubkey */
257  dig->pub = _free(dig->pub);
258  dig->publen = 0;
259  { rpmiob iob = rpmiobNew(0);
260  iob = rpmiobAppend(iob, he->p.argv[ix], 0);
261  xx = pgpArmorUnwrap(iob, (rpmuint8_t **)&dig->pub, &dig->publen);
262  iob = rpmiobFree(iob);
263  }
264  if (xx != PGPARMOR_PUBKEY) {
265  dig->pub = _free(dig->pub);
266  dig->publen = 0;
267  }
268  break;
269  }
270  he->p.ptr = _free(he->p.ptr);
271 
272  /* Retrieve the tag parameters from the signature header. */
273  xx = headerGet(sigh, she, 0);
274  if (she->p.ptr == NULL) {
275  rc = RPMRC_FAIL;
276  goto exit;
277  }
278 /*@-ownedtrans -noeffect@*/
279  xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
280 /*@=ownedtrans =noeffect@*/
281 
282  switch ((rpmSigTag)she->tag) {
283  default: /* XXX keep gcc quiet. */
284 assert(0);
285  /*@notreached@*/ break;
286  case RPMSIGTAG_RSA:
287  /* Parse the parameters from the OpenPGP packets that will be needed. */
288  xx = pgpPktLen(she->p.ui8p, she->c, pp);
289  xx = rpmhkpLoadSignature(NULL, dig, pp);
290  if (dig->signature.version != 3 && dig->signature.version != 4) {
292  _("skipping package %s with unverifiable V%u signature\n"),
293  fn, dig->signature.version);
294  rc = RPMRC_FAIL;
295  goto exit;
296  }
297  xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hrsa);
298  break;
299  case RPMSIGTAG_DSA:
300  /* Parse the parameters from the OpenPGP packets that will be needed. */
301  xx = pgpPktLen(she->p.ui8p, she->c, pp);
302  xx = rpmhkpLoadSignature(NULL, dig, pp);
303  if (dig->signature.version != 3 && dig->signature.version != 4) {
305  _("skipping package %s with unverifiable V%u signature\n"),
306  fn, dig->signature.version);
307  rc = RPMRC_FAIL;
308  goto exit;
309  }
310  xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hdsa);
311  break;
312  case RPMSIGTAG_ECDSA:
313  /* Parse the parameters from the OpenPGP packets that will be needed. */
314  xx = pgpPktLen(she->p.ui8p, she->c, pp);
315  xx = rpmhkpLoadSignature(NULL, dig, pp);
316  if (dig->signature.version != 3 && dig->signature.version != 4) {
318  _("skipping package %s with unverifiable V%u signature\n"),
319  fn, dig->signature.version);
320  rc = RPMRC_FAIL;
321  goto exit;
322  }
323  xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hecdsa);
324  break;
325  case RPMSIGTAG_SHA1:
326  /* XXX dig->hsha? */
327  xx = hBlobDigest(h, dig, PGPHASHALGO_SHA1, &dig->hdsa);
328  break;
329  case RPMSIGTAG_MD5:
330  /* Legacy signatures need the compressed payload in the digest too. */
331  op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
332  (void) rpmswEnter(op, 0);
333  while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
334  dig->nbytes += count;
335  (void) rpmswExit(op, dig->nbytes);
336  op->count--; /* XXX one too many */
337  dig->nbytes += nb; /* XXX include size of header blob. */
338  if (count < 0) {
339  rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
340  fn, Fstrerror(fd));
341  rc = RPMRC_FAIL;
342  goto exit;
343  }
344 
345  /* XXX Steal the digest-in-progress from the file handle. */
346  fdStealDigest(fd, dig);
347  break;
348  }
349 
352  buf[0] = '\0';
353  rc = rpmVerifySignature(dig, buf);
354  switch (rc) {
355  case RPMRC_OK: /* Signature is OK. */
356  rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf);
357  break;
358  case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */
359  case RPMRC_NOKEY: /* Public key is unavailable. */
360 #ifndef DYING
361  /* XXX Print NOKEY/NOTTRUSTED warning only once. */
362  { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
363  rpmlog(lvl, "%s: %s\n", fn, buf);
364  } break;
365  case RPMRC_NOTFOUND: /* Signature is unknown type. */
366  rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf);
367  break;
368 #else
369  case RPMRC_NOTFOUND: /* Signature is unknown type. */
370  case RPMRC_NOSIG: /* Signature is unavailable. */
371 #endif
372  default:
373  case RPMRC_FAIL: /* Signature does not verify. */
374  rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf);
375  break;
376  }
377 
378 exit:
379  if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
380 
381  /* Append (and remap) signature tags to the metadata. */
382  headerMergeLegacySigs(h, sigh);
383 
384  /* Bump reference count for return. */
385  *hdrp = headerLink(h);
386  }
387  (void)headerFree(h);
388  h = NULL;
389 
390  /* Accumulate time reading package header. */
391  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
392  fdstat_op(fd, FDSTAT_READ));
393  (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
394  opsave);
395 
396 #ifdef NOTYET
397  /* Return RPMRC_NOSIG for MANDATORY signature verification. */
398  { rpmSigTag sigtag = pgpGetSigtag(dig);
399  switch (sigtag) {
400  default:
401  rc = RPMRC_NOSIG;
402  /*@fallthrough@*/
403  case RPMSIGTAG_RSA:
404  case RPMSIGTAG_DSA:
405  case RPMSIGTAG_ECDSA:
406  break;
407  }
408  }
409 #endif
410 
411  rpmtsCleanDig(ts);
412  (void)headerFree(sigh);
413  sigh = NULL;
414 
415  return rc;
416 }
417 /*@=mods@*/
FDSTAT_t stats
rpmTagType t
Definition: rpmtag.h:504
rpmTag tag
Definition: rpmtag.h:503
const char ** argv
Definition: rpmtag.h:75
rpmtime_t rpmswExit(rpmop op, ssize_t rc)
Exit timed operation.
Definition: rpmsw.c:264
int headerIsEntry(Header h, rpmTag tag)
Check if tag is in header.
Definition: header.c:1439
const char bson_timestamp_t * ts
Definition: bson.h:1004
void headerMergeLegacySigs(Header h, const Header sigh)
Translate and merge legacy signature tags into header.
Definition: hdrNVR.c:242
int pgpPktLen(const rpmuint8_t *pkt, size_t pleft, pgpPkt pp)
Definition: rpmpgp.c:999
const void * pgpGetSig(pgpDig dig)
Get signature tag data, i.e.
Definition: rpmpgp.c:1412
enum rpmSigTag_e rpmSigTag
Definition: rpmtag.h:474
struct pgpDigParams_s * pgpDigParams
Definition: rpmiotypes.h:101
DIGEST_CTX rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags)
Initialize digest context.
Definition: digest.c:247
int headerGet(Header h, HE_t he, unsigned int flags)
Retrieve extension or tag value from a header.
Definition: header.c:2231
static unsigned int pgpGrab(const rpmuint8_t *s, size_t nbytes)
Return (native-endian) integer from big-endian representation.
Definition: rpmpgp.h:1036
enum pgpHashAlgo_e pgpHashAlgo
9.4.
The Header data structure.
rpmtime_t rpmswAdd(rpmop to, rpmop from)
Sum statistic counters.
Definition: rpmsw.c:280
static rpmVSFlags vsflags
Definition: rpmcache.c:547
rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
Retrieve operation timestamp from a transaction set.
Definition: pkgio.c:133
int pgpSetSig(pgpDig dig, rpmuint32_t sigtag, rpmuint32_t sigtype, const void *sig, rpmuint32_t siglen)
Set signature tag info, i.e.
Definition: rpmpgp.c:1422
enum rpmtsOpX_e rpmtsOpX
Indices for timestamps.
rpmiob rpmiobFree(rpmiob iob)
Destroy a I/O buffer instance.
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
rpmiob rpmiobAppend(rpmiob iob, const char *s, size_t nl)
Append string to I/O buffer.
Definition: rpmiob.c:77
static void fdInitDigest(FD_t fd, pgpHashAlgo hashalgo, int _flags)
Attach digest to fd.
pgpArmor pgpArmorUnwrap(rpmiob iob, rpmuint8_t **pkt, size_t *pktlen)
Parse armored OpenPGP packets from an iob.
Definition: rpmpgp.c:1564
static rpmop fdstat_op(FD_t fd, fdOpX opx)
char * alloca()
struct _HE_s * HE_t
Definition: rpmtag.h:59
pgpVSFlags pgpDigVSFlags
Disabler bits(s) for signature/digest checking.
Definition: rpmpgp.c:1153
void rpmtsCleanDig(rpmts ts)
Free signature verification data.
Definition: pkgio.c:456
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
void * ptr
Definition: rpmtag.h:67
int rpmDigestUpdate(DIGEST_CTX ctx, const void *data, size_t len)
Update context with next plain text buffer.
Definition: digest.c:986
unsigned int * keyids
Definition: package.c:32
int count
Definition: rpmsw.h:41
static void fdSetDig(FD_t fd, pgpDig dig)
unsigned char rpmuint8_t
Private int typedefs to avoid C99 portability issues.
Definition: rpmiotypes.h:26
rpmTagData p
Definition: rpmtag.h:506
struct pgpPkt_s * pgpPkt
Definition: rpmiotypes.h:93
pgpDigParams pgpGetSignature(pgpDig dig)
Return OpenPGP signature parameters.
Definition: rpmpgp.c:1392
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char *fn, Header *hdrp)
Return package header from file handle, verifying digests/signatures.
Definition: package.c:114
rpmuint32_t pgpGetSigtag(pgpDig dig)
Get signature tag.
Definition: rpmpgp.c:1402
Digest private data.
Definition: digest.c:130
The FD_t File Handle data structure.
struct pgpDig_s * pgpDig
Definition: rpmiotypes.h:97
rpmTagCount c
Definition: rpmtag.h:507
Generate and verify rpm package signatures.
pgpVSFlags rpmVSFlags
Bit(s) to control digest and signature verification.
Definition: rpmts.h:35
Header headerFree(Header h)
Dereference a header instance.
int headerGetMagic(Header h, unsigned char **magicp, size_t *nmagicp)
Return header magic.
Definition: header.c:1162
rpmRC rpmVerifySignature(void *_dig, char *result)
Verify a signature from a package.
Definition: signature.c:1094
int rpmswEnter(rpmop op, ssize_t rc)
Enter timed operation.
Definition: rpmsw.c:248
const char const bson const bson * op
Definition: mongo.h:505
struct rpmop_s * rpmop
Definition: rpmsw.h:24
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
static unsigned int nextkeyid
Definition: package.c:40
rpmuint8_t * ui8p
Definition: rpmtag.h:68
Cumulative statistics for an operation.
Definition: rpmsw.h:39
rpmiob rpmiobNew(size_t len)
Create an I/O buffer.
Definition: rpmiob.c:44
Header headerLink(Header h)
Reference a header instance.
enum rpmRC_e rpmRC
RPM return codes.
Definition: rpmtag.h:502
const char const int i
Definition: bson.h:778
Methods to handle package elements.
rpmtime_t rpmswSub(rpmop to, rpmop from)
Subtract statistic counters.
Definition: rpmsw.c:292
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
#define _chk(_mask)
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:60
Structures and prototypes used for an "rpmts" transaction set.
static unsigned int nkeyids
Definition: package.c:38
#define _(Text)
Definition: system.h:29
static int pgpStashKeyid(pgpDig dig)
Remember current key id.
Definition: package.c:47
static int hBlobDigest(Header h, pgpDig dig, pgpHashAlgo hash_algo, DIGEST_CTX *ctxp)
Definition: package.c:82
rpmRC rpmpkgRead(const char *fn, FD_t fd, void *ptr, const char **msg)
Read item from file descriptor.
Definition: pkgio.c:1674
enum rpmTag_e rpmTag
Definition: rpmtag.h:470
static void fdStealDigest(FD_t fd, pgpDig dig)
pgpDig rpmtsDig(rpmts ts)
Get OpenPGP packet parameters, i.e.
Definition: pkgio.c:441
void * pgpStatsAccumulator(pgpDig dig, int opx)
Return pgpDig container accumulator structure.
Definition: rpmpgp.c:1436
static unsigned int nkeyids_max
Definition: package.c:36
int rpmhkpLoadSignature(rpmhkp hkp, pgpDig dig, pgpPkt pp)
Definition: rpmhkp.c:461
#define xrealloc
Definition: system.h:35