rpm 5.3.7
|
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 #define _RPMHKP_INTERNAL /* XXX internal prototypes. */ 00013 #include <rpmhkp.h> 00014 00015 #include <rpmtag.h> 00016 #include <rpmtypes.h> 00017 #include <pkgio.h> 00018 #include "signature.h" /* XXX rpmVerifySignature */ 00019 00020 #include "rpmts.h" 00021 00022 #include "debug.h" 00023 00024 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) 00025 00026 /*@access pgpDig @*/ 00027 /*@access pgpDigParams @*/ 00028 /*@access Header @*/ /* XXX compared with NULL */ 00029 /*@access FD_t @*/ /* XXX void * */ 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 unsigned ix; 00092 Header h = NULL; 00093 const char * msg = NULL; 00094 rpmVSFlags vsflags; 00095 rpmRC rc = RPMRC_FAIL; /* assume failure */ 00096 rpmop opsave = memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave)); 00097 int xx; 00098 pgpPkt pp = alloca(sizeof(*pp)); 00099 00100 if (hdrp) *hdrp = NULL; 00101 00102 assert(dig != NULL); 00103 (void) fdSetDig(fd, dig); 00104 00105 /* Snapshot current I/O counters (cached persistent I/O reuses counters) */ 00106 (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ)); 00107 00108 { const char item[] = "Lead"; 00109 msg = NULL; 00110 rc = rpmpkgRead(item, fd, NULL, &msg); 00111 switch (rc) { 00112 default: 00113 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); 00114 /*@fallthrough@*/ 00115 case RPMRC_NOTFOUND: 00116 msg = _free(msg); 00117 goto exit; 00118 /*@notreached@*/ break; 00119 case RPMRC_OK: 00120 break; 00121 } 00122 msg = _free(msg); 00123 } 00124 00125 { const char item[] = "Signature"; 00126 msg = NULL; 00127 rc = rpmpkgRead(item, fd, &sigh, &msg); 00128 switch (rc) { 00129 default: 00130 rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item, 00131 (msg && *msg ? msg : _("read failed\n"))); 00132 msg = _free(msg); 00133 goto exit; 00134 /*@notreached@*/ break; 00135 case RPMRC_OK: 00136 if (sigh == NULL) { 00137 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn); 00138 rc = RPMRC_FAIL; 00139 goto exit; 00140 } 00141 break; 00142 } 00143 msg = _free(msg); 00144 } 00145 00146 #define _chk(_mask) (she->tag == 0 && !(vsflags & (_mask))) 00147 00148 /* 00149 * Figger the most effective available signature. 00150 * Prefer signatures over digests, then header-only over header+payload. 00151 * DSA will be preferred over RSA if both exist because tested first. 00152 * Note that NEEDPAYLOAD prevents header+payload signatures and digests. 00153 */ 00154 she->tag = 0; 00155 opx = 0; 00156 vsflags = pgpDigVSFlags; 00157 if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) { 00158 she->tag = (rpmTag)RPMSIGTAG_DSA; 00159 } else 00160 if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) { 00161 she->tag = (rpmTag)RPMSIGTAG_RSA; 00162 } else 00163 if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) { 00164 she->tag = (rpmTag)RPMSIGTAG_SHA1; 00165 } else 00166 if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) && 00167 headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5)) 00168 { 00169 she->tag = (rpmTag)RPMSIGTAG_MD5; 00170 fdInitDigest(fd, PGPHASHALGO_MD5, 0); 00171 opx = RPMTS_OP_DIGEST; 00172 } 00173 00174 /* Read the metadata, computing digest(s) on the fly. */ 00175 h = NULL; 00176 msg = NULL; 00177 00178 /* XXX stats will include header i/o and setup overhead. */ 00179 /* XXX repackaged packages have appended tags, legacy dig/sig check fails */ 00180 if (opx > 0) { 00181 op = pgpStatsAccumulator(dig, opx); 00182 (void) rpmswEnter(op, 0); 00183 } 00184 /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */ 00185 nb = fd->stats->ops[FDSTAT_READ].bytes; 00186 { const char item[] = "Header"; 00187 msg = NULL; 00188 rc = rpmpkgRead(item, fd, &h, &msg); 00189 if (rc != RPMRC_OK) { 00190 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); 00191 msg = _free(msg); 00192 goto exit; 00193 } 00194 msg = _free(msg); 00195 } 00196 nb = fd->stats->ops[FDSTAT_READ].bytes - nb; 00197 /*@=type@*/ 00198 if (opx > 0 && op != NULL) { 00199 (void) rpmswExit(op, nb); 00200 op = NULL; 00201 } 00202 00203 /* Any digests or signatures to check? */ 00204 if (she->tag == 0) { 00205 rc = RPMRC_OK; 00206 goto exit; 00207 } 00208 00209 dig->nbytes = 0; 00210 00211 /* Fish out the autosign pubkey (if present). */ 00212 he->tag = RPMTAG_PUBKEYS; 00213 xx = headerGet(h, he, 0); 00214 if (xx && he->p.argv != NULL && he->c > 0) 00215 switch (he->t) { 00216 default: 00217 break; 00218 case RPM_STRING_ARRAY_TYPE: 00219 ix = he->c - 1; /* XXX FIXME: assumes last pubkey */ 00220 dig->pub = _free(dig->pub); 00221 dig->publen = 0; 00222 { rpmiob iob = rpmiobNew(0); 00223 iob = rpmiobAppend(iob, he->p.argv[ix], 0); 00224 xx = pgpArmorUnwrap(iob, (void *)&dig->pub, &dig->publen); 00225 iob = rpmiobFree(iob); 00226 } 00227 if (xx != PGPARMOR_PUBKEY) { 00228 dig->pub = _free(dig->pub); 00229 dig->publen = 0; 00230 } 00231 break; 00232 } 00233 he->p.ptr = _free(he->p.ptr); 00234 00235 /* Retrieve the tag parameters from the signature header. */ 00236 xx = headerGet(sigh, she, 0); 00237 if (she->p.ptr == NULL) { 00238 rc = RPMRC_FAIL; 00239 goto exit; 00240 } 00241 /*@-ownedtrans -noeffect@*/ 00242 xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c); 00243 /*@=ownedtrans =noeffect@*/ 00244 00245 switch ((rpmSigTag)she->tag) { 00246 default: /* XXX keep gcc quiet. */ 00247 assert(0); 00248 /*@notreached@*/ break; 00249 case RPMSIGTAG_RSA: 00250 /* Parse the parameters from the OpenPGP packets that will be needed. */ 00251 xx = pgpPktLen(she->p.ptr, she->c, pp); 00252 xx = rpmhkpLoadSignature(NULL, dig, pp); 00253 if (dig->signature.version != 3 && dig->signature.version != 4) { 00254 rpmlog(RPMLOG_ERR, 00255 _("skipping package %s with unverifiable V%u signature\n"), 00256 fn, dig->signature.version); 00257 rc = RPMRC_FAIL; 00258 goto exit; 00259 } 00260 { void * uh = NULL; 00261 rpmTagType uht; 00262 rpmTagCount uhc; 00263 unsigned char * hmagic = NULL; 00264 size_t nmagic = 0; 00265 00266 he->tag = RPMTAG_HEADERIMMUTABLE; 00267 xx = headerGet(h, he, 0); 00268 uht = he->t; 00269 uh = he->p.ptr; 00270 uhc = he->c; 00271 if (!xx) 00272 break; 00273 (void) headerGetMagic(NULL, &hmagic, &nmagic); 00274 op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00275 (void) rpmswEnter(op, 0); 00276 dig->hdrctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE); 00277 if (hmagic && nmagic > 0) { 00278 (void) rpmDigestUpdate(dig->hdrctx, hmagic, nmagic); 00279 dig->nbytes += nmagic; 00280 } 00281 (void) rpmDigestUpdate(dig->hdrctx, uh, uhc); 00282 dig->nbytes += uhc; 00283 (void) rpmswExit(op, dig->nbytes); 00284 op->count--; /* XXX one too many */ 00285 uh = _free(uh); 00286 } break; 00287 case RPMSIGTAG_DSA: 00288 /* Parse the parameters from the OpenPGP packets that will be needed. */ 00289 xx = pgpPktLen(she->p.ptr, she->c, pp); 00290 xx = rpmhkpLoadSignature(NULL, dig, pp); 00291 if (dig->signature.version != 3 && dig->signature.version != 4) { 00292 rpmlog(RPMLOG_ERR, 00293 _("skipping package %s with unverifiable V%u signature\n"), 00294 fn, dig->signature.version); 00295 rc = RPMRC_FAIL; 00296 goto exit; 00297 } 00298 /*@fallthrough@*/ 00299 case RPMSIGTAG_SHA1: 00300 { void * uh = NULL; 00301 rpmTagType uht; 00302 rpmTagCount uhc; 00303 unsigned char * hmagic = NULL; 00304 size_t nmagic = 0; 00305 00306 he->tag = RPMTAG_HEADERIMMUTABLE; 00307 xx = headerGet(h, he, 0); 00308 uht = he->t; 00309 uh = he->p.ptr; 00310 uhc = he->c; 00311 if (!xx) 00312 break; 00313 (void) headerGetMagic(NULL, &hmagic, &nmagic); 00314 op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00315 (void) rpmswEnter(op, 0); 00316 dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); 00317 if (hmagic && nmagic > 0) { 00318 (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic); 00319 dig->nbytes += nmagic; 00320 } 00321 (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc); 00322 dig->nbytes += uhc; 00323 (void) rpmswExit(op, dig->nbytes); 00324 if ((rpmSigTag)she->tag == RPMSIGTAG_SHA1) 00325 op->count--; /* XXX one too many */ 00326 uh = _free(uh); 00327 } break; 00328 case RPMSIGTAG_MD5: 00329 /* Legacy signatures need the compressed payload in the digest too. */ 00330 op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00331 (void) rpmswEnter(op, 0); 00332 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) 00333 dig->nbytes += count; 00334 (void) rpmswExit(op, dig->nbytes); 00335 op->count--; /* XXX one too many */ 00336 dig->nbytes += nb; /* XXX include size of header blob. */ 00337 if (count < 0) { 00338 rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), 00339 fn, Fstrerror(fd)); 00340 rc = RPMRC_FAIL; 00341 goto exit; 00342 } 00343 00344 /* XXX Steal the digest-in-progress from the file handle. */ 00345 fdStealDigest(fd, dig); 00346 break; 00347 } 00348 00351 buf[0] = '\0'; 00352 rc = rpmVerifySignature(dig, buf); 00353 switch (rc) { 00354 case RPMRC_OK: /* Signature is OK. */ 00355 rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf); 00356 break; 00357 case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ 00358 case RPMRC_NOKEY: /* Public key is unavailable. */ 00359 /* XXX Print NOKEY/NOTTRUSTED warning only once. */ 00360 { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING); 00361 rpmlog(lvl, "%s: %s\n", fn, buf); 00362 } break; 00363 case RPMRC_NOTFOUND: /* Signature is unknown type. */ 00364 rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf); 00365 break; 00366 default: 00367 case RPMRC_FAIL: /* Signature does not verify. */ 00368 rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf); 00369 break; 00370 } 00371 00372 exit: 00373 if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { 00374 00375 /* Append (and remap) signature tags to the metadata. */ 00376 headerMergeLegacySigs(h, sigh); 00377 00378 /* Bump reference count for return. */ 00379 *hdrp = headerLink(h); 00380 } 00381 (void)headerFree(h); 00382 h = NULL; 00383 00384 /* Accumulate time reading package header. */ 00385 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR), 00386 fdstat_op(fd, FDSTAT_READ)); 00387 (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR), 00388 opsave); 00389 00390 rpmtsCleanDig(ts); 00391 (void)headerFree(sigh); 00392 sigh = NULL; 00393 return rc; 00394 } 00395 /*@=mods@*/