rpm 5.2.1
|
00001 00005 #include "system.h" 00006 00007 #include <netinet/in.h> 00008 00009 #include <rpmio_internal.h> 00010 #include <rpmcb.h> /* XXX fnpyKey */ 00011 00012 #include <rpmtag.h> 00013 #include <rpmtypes.h> 00014 #include <pkgio.h> 00015 #include "signature.h" /* XXX rpmVerifySignature */ 00016 00017 #include "rpmts.h" 00018 00019 #include "debug.h" 00020 00021 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) 00022 00023 /*@access pgpDig @*/ 00024 /*@access pgpDigParams @*/ 00025 /*@access Header @*/ /* XXX compared with NULL */ 00026 /*@access FD_t @*/ /* XXX void * */ 00027 00028 /*@unchecked@*/ 00029 static int _print_pkts = 0; 00030 00031 /*@unchecked@*/ 00032 static unsigned int nkeyids_max = 256; 00033 /*@unchecked@*/ 00034 static unsigned int nkeyids = 0; 00035 /*@unchecked@*/ 00036 static unsigned int nextkeyid = 0; 00037 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00038 unsigned int * keyids = NULL; 00039 00045 static int pgpStashKeyid(pgpDig dig) 00046 /*@globals nextkeyid, nkeyids, keyids @*/ 00047 /*@modifies nextkeyid, nkeyids, keyids @*/ 00048 { 00049 pgpDigParams sigp = pgpGetSignature(dig); 00050 const void * sig = pgpGetSig(dig); 00051 unsigned int keyid; 00052 unsigned int i; 00053 00054 if (sig == NULL || dig == NULL || sigp == NULL) 00055 return 0; 00056 00057 keyid = pgpGrab(sigp->signid+4, 4); 00058 if (keyid == 0) 00059 return 0; 00060 00061 if (keyids != NULL) 00062 for (i = 0; i < nkeyids; i++) { 00063 if (keyid == keyids[i]) 00064 return 1; 00065 } 00066 00067 if (nkeyids < nkeyids_max) { 00068 nkeyids++; 00069 keyids = xrealloc(keyids, nkeyids * sizeof(*keyids)); 00070 } 00071 if (keyids) /* XXX can't happen */ 00072 keyids[nextkeyid] = keyid; 00073 nextkeyid++; 00074 nextkeyid %= nkeyids_max; 00075 00076 return 0; 00077 } 00078 00079 /*@-mods@*/ 00080 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp) 00081 { 00082 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00083 HE_t she = memset(alloca(sizeof(*she)), 0, sizeof(*she)); 00084 pgpDig dig = rpmtsDig(ts); 00085 char buf[8*BUFSIZ]; 00086 ssize_t count; 00087 Header sigh = NULL; 00088 rpmtsOpX opx; 00089 rpmop op = NULL; 00090 size_t nb; 00091 Header h = NULL; 00092 const char * msg = NULL; 00093 rpmVSFlags vsflags; 00094 rpmRC rc = RPMRC_FAIL; /* assume failure */ 00095 rpmop opsave = memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave)); 00096 int xx; 00097 00098 if (hdrp) *hdrp = NULL; 00099 00100 assert(dig != NULL); 00101 (void) fdSetDig(fd, dig); 00102 00103 /* Snapshot current I/O counters (cached persistent I/O reuses counters) */ 00104 (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ)); 00105 00106 { const char item[] = "Lead"; 00107 msg = NULL; 00108 rc = rpmpkgRead(item, fd, NULL, &msg); 00109 switch (rc) { 00110 default: 00111 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); 00112 /*@fallthrough@*/ 00113 case RPMRC_NOTFOUND: 00114 msg = _free(msg); 00115 goto exit; 00116 /*@notreached@*/ break; 00117 case RPMRC_OK: 00118 break; 00119 } 00120 msg = _free(msg); 00121 } 00122 00123 { const char item[] = "Signature"; 00124 msg = NULL; 00125 rc = rpmpkgRead(item, fd, &sigh, &msg); 00126 switch (rc) { 00127 default: 00128 rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item, 00129 (msg && *msg ? msg : _("read failed\n"))); 00130 msg = _free(msg); 00131 goto exit; 00132 /*@notreached@*/ break; 00133 case RPMRC_OK: 00134 if (sigh == NULL) { 00135 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn); 00136 rc = RPMRC_FAIL; 00137 goto exit; 00138 } 00139 break; 00140 } 00141 msg = _free(msg); 00142 } 00143 00144 #define _chk(_mask) (she->tag == 0 && !(vsflags & (_mask))) 00145 00146 /* 00147 * Figger the most effective available signature. 00148 * Prefer signatures over digests, then header-only over header+payload. 00149 * DSA will be preferred over RSA if both exist because tested first. 00150 * Note that NEEDPAYLOAD prevents header+payload signatures and digests. 00151 */ 00152 she->tag = 0; 00153 opx = 0; 00154 vsflags = pgpDigVSFlags; 00155 if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) { 00156 she->tag = (rpmTag)RPMSIGTAG_DSA; 00157 } else 00158 if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) { 00159 she->tag = (rpmTag)RPMSIGTAG_RSA; 00160 } else 00161 if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) { 00162 she->tag = (rpmTag)RPMSIGTAG_SHA1; 00163 } else 00164 if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) && 00165 headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5)) 00166 { 00167 she->tag = (rpmTag)RPMSIGTAG_MD5; 00168 fdInitDigest(fd, PGPHASHALGO_MD5, 0); 00169 opx = RPMTS_OP_DIGEST; 00170 } 00171 00172 /* Read the metadata, computing digest(s) on the fly. */ 00173 h = NULL; 00174 msg = NULL; 00175 00176 /* XXX stats will include header i/o and setup overhead. */ 00177 /* XXX repackaged packages have appended tags, legacy dig/sig check fails */ 00178 if (opx > 0) { 00179 op = pgpStatsAccumulator(dig, opx); 00180 (void) rpmswEnter(op, 0); 00181 } 00182 /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */ 00183 nb = fd->stats->ops[FDSTAT_READ].bytes; 00184 { const char item[] = "Header"; 00185 msg = NULL; 00186 rc = rpmpkgRead(item, fd, &h, &msg); 00187 if (rc != RPMRC_OK) { 00188 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); 00189 msg = _free(msg); 00190 goto exit; 00191 } 00192 msg = _free(msg); 00193 } 00194 nb = fd->stats->ops[FDSTAT_READ].bytes - nb; 00195 /*@=type@*/ 00196 if (opx > 0 && op != NULL) { 00197 (void) rpmswExit(op, nb); 00198 op = NULL; 00199 } 00200 00201 /* Any digests or signatures to check? */ 00202 if (she->tag == 0) { 00203 rc = RPMRC_OK; 00204 goto exit; 00205 } 00206 00207 dig->nbytes = 0; 00208 00209 /* Retrieve the tag parameters from the signature header. */ 00210 xx = headerGet(sigh, she, 0); 00211 if (she->p.ptr == NULL) { 00212 rc = RPMRC_FAIL; 00213 goto exit; 00214 } 00215 /*@-ownedtrans -noeffect@*/ 00216 xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c); 00217 /*@=ownedtrans =noeffect@*/ 00218 00219 switch ((rpmSigTag)she->tag) { 00220 default: /* XXX keep gcc quiet. */ 00221 assert(0); 00222 /*@notreached@*/ break; 00223 case RPMSIGTAG_RSA: 00224 /* Parse the parameters from the OpenPGP packets that will be needed. */ 00225 xx = pgpPrtPkts(she->p.ptr, she->c, dig, (_print_pkts & rpmIsDebug())); 00226 if (dig->signature.version != 3 && dig->signature.version != 4) { 00227 rpmlog(RPMLOG_ERR, 00228 _("skipping package %s with unverifiable V%u signature\n"), 00229 fn, dig->signature.version); 00230 rc = RPMRC_FAIL; 00231 goto exit; 00232 } 00233 { void * uh = NULL; 00234 rpmTagType uht; 00235 rpmTagCount uhc; 00236 unsigned char * hmagic = NULL; 00237 size_t nmagic = 0; 00238 00239 he->tag = RPMTAG_HEADERIMMUTABLE; 00240 xx = headerGet(h, he, 0); 00241 uht = he->t; 00242 uh = he->p.ptr; 00243 uhc = he->c; 00244 if (!xx) 00245 break; 00246 (void) headerGetMagic(NULL, &hmagic, &nmagic); 00247 op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00248 (void) rpmswEnter(op, 0); 00249 dig->hdrctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE); 00250 if (hmagic && nmagic > 0) { 00251 (void) rpmDigestUpdate(dig->hdrctx, hmagic, nmagic); 00252 dig->nbytes += nmagic; 00253 } 00254 (void) rpmDigestUpdate(dig->hdrctx, uh, uhc); 00255 dig->nbytes += uhc; 00256 (void) rpmswExit(op, dig->nbytes); 00257 op->count--; /* XXX one too many */ 00258 uh = _free(uh); 00259 } break; 00260 case RPMSIGTAG_DSA: 00261 /* Parse the parameters from the OpenPGP packets that will be needed. */ 00262 xx = pgpPrtPkts(she->p.ptr, she->c, dig, (_print_pkts & rpmIsDebug())); 00263 if (dig->signature.version != 3 && dig->signature.version != 4) { 00264 rpmlog(RPMLOG_ERR, 00265 _("skipping package %s with unverifiable V%u signature\n"), 00266 fn, dig->signature.version); 00267 rc = RPMRC_FAIL; 00268 goto exit; 00269 } 00270 /*@fallthrough@*/ 00271 case RPMSIGTAG_SHA1: 00272 { void * uh = NULL; 00273 rpmTagType uht; 00274 rpmTagCount uhc; 00275 unsigned char * hmagic = NULL; 00276 size_t nmagic = 0; 00277 00278 he->tag = RPMTAG_HEADERIMMUTABLE; 00279 xx = headerGet(h, he, 0); 00280 uht = he->t; 00281 uh = he->p.ptr; 00282 uhc = he->c; 00283 if (!xx) 00284 break; 00285 (void) headerGetMagic(NULL, &hmagic, &nmagic); 00286 op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00287 (void) rpmswEnter(op, 0); 00288 dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); 00289 if (hmagic && nmagic > 0) { 00290 (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic); 00291 dig->nbytes += nmagic; 00292 } 00293 (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc); 00294 dig->nbytes += uhc; 00295 (void) rpmswExit(op, dig->nbytes); 00296 if ((rpmSigTag)she->tag == RPMSIGTAG_SHA1) 00297 op->count--; /* XXX one too many */ 00298 uh = _free(uh); 00299 } break; 00300 case RPMSIGTAG_MD5: 00301 /* Legacy signatures need the compressed payload in the digest too. */ 00302 op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00303 (void) rpmswEnter(op, 0); 00304 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) 00305 dig->nbytes += count; 00306 (void) rpmswExit(op, dig->nbytes); 00307 op->count--; /* XXX one too many */ 00308 dig->nbytes += nb; /* XXX include size of header blob. */ 00309 if (count < 0) { 00310 rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), 00311 fn, Fstrerror(fd)); 00312 rc = RPMRC_FAIL; 00313 goto exit; 00314 } 00315 00316 /* XXX Steal the digest-in-progress from the file handle. */ 00317 fdStealDigest(fd, dig); 00318 break; 00319 } 00320 00323 buf[0] = '\0'; 00324 rc = rpmVerifySignature(dig, buf); 00325 switch (rc) { 00326 case RPMRC_OK: /* Signature is OK. */ 00327 rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf); 00328 break; 00329 case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ 00330 case RPMRC_NOKEY: /* Public key is unavailable. */ 00331 /* XXX Print NOKEY/NOTTRUSTED warning only once. */ 00332 { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING); 00333 rpmlog(lvl, "%s: %s\n", fn, buf); 00334 } break; 00335 case RPMRC_NOTFOUND: /* Signature is unknown type. */ 00336 rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf); 00337 break; 00338 default: 00339 case RPMRC_FAIL: /* Signature does not verify. */ 00340 rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf); 00341 break; 00342 } 00343 00344 exit: 00345 if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { 00346 00347 /* Append (and remap) signature tags to the metadata. */ 00348 headerMergeLegacySigs(h, sigh); 00349 00350 /* Bump reference count for return. */ 00351 *hdrp = headerLink(h); 00352 } 00353 (void)headerFree(h); 00354 h = NULL; 00355 00356 /* Accumulate time reading package header. */ 00357 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR), 00358 fdstat_op(fd, FDSTAT_READ)); 00359 (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR), 00360 opsave); 00361 00362 rpmtsCleanDig(ts); 00363 (void)headerFree(sigh); 00364 sigh = NULL; 00365 return rc; 00366 } 00367 /*@=mods@*/