⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgprngread.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * The files are assigned priorities for fetching.  The default is
 * that the first opened file is highest and subsequent files are of
 * lower priority.  This is done by having each Ringfile keep a mask
 * of higher-priority RingFiles.  We walk along the list until we hit
 * a RingFile whose higher-priority mask doesn't include any files that
 * the object being sought is in.
 *
 * The packet fetched must pass the following validity checks:
 * - It must be of the given packet type.
 * - It must be no longer than "maxlen".
 * - If those pass, it must be read into memory successfully.
 * - It must then pass the caller-supplied "verify" function,
 *   which checks object-type-specific information against the
 *   summary information stored in the RingObject.
 *
 * Question: what to return when the avoidmask doesn't allow anything to
 * be fetched?  Is this case just an error?
 */
static void const *
ringFetchPacket(RingPool *pool, union RingObject const *obj,
	PGPVirtMask *avoidmask, int pkttype, PGPSize maxlen, PGPSize *lenp,
	int (*verify)(RingPool *pool, union RingObject const *, PGPByte const *,
				  size_t))
{
	RingFile *file;
	FilePos const *pos;
	PGPSize len, len1;
	int i;
	void *p;

	/* find highest-priority fetchable file */
	file = ringBestFile(pool, obj, avoidmask);
	if (!file) {
		*lenp = (size_t)0;
		return NULL;	/* Is this The Right Thing? */
	}

	pos = ringFilePos(obj, file);
	pgpAssert(pos);

	/* If it's in memory, that was easy... */
	if (pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask)) {
		pgpAssert (!verify
		        || verify(pool, obj, (PGPByte *)pos->ptr.buf, pos->fpos) == 0);
		*lenp = pos->fpos;
		return pos->ptr.buf;
	}

	/* We now have highest-priority fetchable file */
	pgpAssert(file->f);
	if (pgpFileSeek(file->f, pos->fpos, SEEK_SET) != 0) {
		i = kPGPError_FileOpFailed;
		goto err;
	}
	i = pktByteGet(file->f, &len, &len1, (PGPSize *)NULL);
	if (i <= 0)
		goto err;
	if (PKTBYTE_TYPE(i) != pkttype || len > maxlen) {
		i = kPGPError_BadPacket;
		goto err;
	}
	p = ringReserve(pool, (size_t)len);
	if (!p)
		goto errmem;	/* ringErr() already called */
	pool->pktbuflen = len;
	i = pktBodyRead(pool->pktbuf, len, len1, file->f);
	if ((size_t)i != (size_t)len) {
		i = pgpFileError(file->f) ? kPGPError_ReadFailed :
					    kPGPError_EOF;
		goto err;
	}
	p = pool->pktbuf;

	/* Okay, now verify with supplied function */
	if (verify && (i = verify(pool, obj, (PGPByte const *)p, len)) != 0) {
		if (pkttype == PKTBYTE_SECKEY
		    && len
		    && obj->g.flags & SECF_VERSION_BUG
		    && ((PGPByte *)p)[0] == PGPVERSION_3) {
			/*
			 * Failure may be due to version bug; fix and try
			 * again.  If success, put it back so we behave
			 * consistently.  Verify doesn't always fail with
			 * version bug, it depends on whether sec or pub was
			 * seen first.
			 */
			((PGPByte *)p)[0] = PGPVERSION_2;
			if (verify &&
			    (i = verify(pool, obj, (PGPByte const *)p, len)) != 0)
				goto err;
			((PGPByte *)p)[0] = PGPVERSION_3;
		} else {
			goto err;
		}
	}

	/* Success! */
	*lenp = len;
	return p;

	/* Error cases (out of line) */
err:
	ringErr(file, pos->fpos, (PGPError)i);
errmem:
	*lenp = 0;
	return NULL;
}

/*
 * The verify functions here should *never* fail under normal
 * conditions.  They fail only if the keyring file has been
 * changed while PGP is accessing it (which causes a fatal error).
 * Did I mention that this code is *paranoid*?
 * ("The computer is your friend.  The computer wants you to be happy.")
 *
 * They operate by re-parsing the fetched data and checking that
 * the cached data matches the data just fetched.
 */

/* Verify that the key we just read looks like the one we wanted to read. */
static int
ringKeyVerify(RingPool *pool, union RingObject const *obj,
	PGPByte const *p, size_t len)
{
	int i;
	PGPByte pkalg, keyID[8], fp20n[20];
	PGPUInt16 keybits, validity;
	PGPUInt32 tstamp;
	PGPByte v3;

	i = ringKeyParse(pool->context, p, len, &pkalg, keyID, fp20n, &keybits,
	                 &tstamp, &validity, &v3, 0);

	if (memcmp(keyID, obj->k.keyID, 8) == 0
		&& fp20n[0] == obj->k.fp20n
	    && keybits  == obj->k.keybits
	    && tstamp   == obj->k.tstamp
/*	    && validity == obj->k.validity  Validity sometimes stored elsewhere */
	    && pkalg    == obj->k.pkalg
		&& v3		== !!KEYISV3(&obj->k)
	    && (i == 0) == !(obj->g.flags & KEYF_ERROR))
		return 0;	/* All copascetic */

	return kPGPError_BadPacket;
}

/* Verify that the secret we just read looks like the one we wanted to read. */
static int
ringSecVerify(RingPool *pool, union RingObject const *obj,
	PGPByte const *p, size_t len)
{
	int i;
	PGPByte pkalg, keyID[8], fp20n[20];
	PGPUInt16 keybits, validity;
	PGPUInt32 tstamp;
	PGPByte v3;
	union RingObject *key = obj->g.up;

	pgpAssert(OBJISSEC(obj));
	pgpAssert(OBJISKEY(key));

	i = ringKeyParse(pool->context, p, len, &pkalg, keyID, fp20n, &keybits,
	                 &tstamp, &validity, &v3, 1);

	if (ringHashBuf(p, len) == obj->c.hash
	    && memcmp(keyID, key->k.keyID, 8) == 0
		&& fp20n[0] == key->k.fp20n
	    && keybits  == key->k.keybits
	    && tstamp   == key->k.tstamp
/*	    && validity == key->k.validity	Validity sometimes stored elsewhere */
	    && pkalg    == key->k.pkalg
		&& v3		== !!KEYISV3(&key->k)
	    && (i == 0) == !(key->g.flags & KEYF_ERROR))
		return 0;	/* All copascetic */

	return kPGPError_BadPacket;
}

/*
 * Verify that the signature we just read looks like the one we wanted to read.
 */
static int
ringSigVerify(RingPool *pool, union RingObject const *obj,
	PGPByte const *p, size_t len)
{
	int i;
	PGPByte pkalg, keyID[8];
	PGPUInt32 tstamp;
	PGPUInt32 sigvalidity;
	size_t extralen;
	PGPByte type, hashalg;
	PGPByte version;
	PGPBoolean exportable;
	PGPBoolean revocable;
	PGPBoolean hasRegExp;
	PGPBoolean isX509;
	PGPBoolean primaryUID;
	PGPByte trustLevel;
	PGPByte trustValue;

	(void) pool;

	i = ringSigParse(p, len, &pkalg, keyID, &tstamp, &sigvalidity,
	                 &type, &hashalg, &extralen, &version, &exportable,
					 &revocable, &trustLevel, &trustValue, &hasRegExp,
					 &isX509, &primaryUID);
	/* Allow mismatch on keyid on X509 sigs */
	if ((isX509 || memcmp(keyID, obj->s.by->k.keyID, 8) == 0)
		&& version == obj->s.version
	    && tstamp == obj->s.tstamp
	    && sigvalidity == obj->s.sigvalidity
	    && type == obj->s.type
	    && hashalg == obj->s.hashalg
	    && (extralen == 5) == !(obj->g.flags & SIGF_NONFIVE)
	    && (i == 0) == !(obj->g.flags & SIGF_ERROR)
		&& (!exportable == !SIGISEXPORTABLE(&obj->s))
		&& (!revocable == !SIGISREVOCABLE(&obj->s))
		&& (!hasRegExp == !SIGUSESREGEXP(&obj->s))
		&& (!isX509 == !SIGISX509(&obj->s))
		&& (!primaryUID == !SIGISPRIMARYUID(&obj->s)))
		return 0;	/* All copascetic */

	return kPGPError_BadPacket;
}

/*
 * Verify that the CRL we just read looks like the one we wanted to read.
 */
static int
ringCRLVerify(RingPool *pool, union RingObject const *obj,
	PGPByte const *p, size_t len)
{
	PGPByte version;
	PGPByte type;
	PGPUInt32 tstamp;
	PGPUInt32 tstampnext;
	PGPByte const *dpoint;
	PGPSize dpointlen;

	(void) pool;

	(void)ringCRLParse(pool, p, len, &version, &type, &tstamp, &tstampnext,
					   &dpoint, &dpointlen);

	if (ringHashBuf(p, len) == obj->r.hash
		&& version == obj->r.version
		&& (type == PGPCRLTYPE_X509 ||
			type == PGPCRLTYPE_X509DPOINT) == CRLISX509(&obj->r)
		&& (type == PGPCRLTYPE_X509DPOINT) == CRLHASDPOINT(&obj->r)
		&& (!CRLHASDPOINT(&obj->r) ||
			ringHashBuf(dpoint, dpointlen) == obj->r.dpointhash)
		&& tstamp == obj->r.tstamp
		&& tstampnext == obj->r.tstampnext
		)
		return 0;	/* All copascetic */

	return kPGPError_BadPacket;
}

/*
 * Verify that the unknown we just read looks like the one we wanted to read.
 */
static int
ringUnkVerify(RingPool *pool, union RingObject const *obj,
	PGPByte const *p, size_t len)
{
	(void) pool;

	if (ringHashBuf(p, len) == obj->u.hash)
		return 0;	/* All copascetic */

	return kPGPError_BadPacket;
}

/*
 * Getting names is special due to the in-memory cache.
 * We don't have to support "avoidmask", though.
 *
 * Return a pointer to a name string.  Note that the string is NOT
 * null-terminated; all 256 values are legal!  The "lenp" argument
 * returns the length.  Tries to get it from memory if possible,
 * then tries to load it into the cache.  If it can't load it into
 * the preferred file cache, load it into the pktbuf.  If even
 * that fails, try to find another cache that it wil fit into.
 *
 * (Note: although strings are not in general null-terminated, hence we
 * return a length field, we do in fact put a null character at name[length]
 * so that callers can be sure that there is a null either within or just
 * beyond the name itself.  This facilitates our regexp matching.)
 *
 * Note that ringNamesDiffer() uses the fact that this either returns
 * with NAMEISCACHED(name) true, *or* the buffer returned is the
 * pktbuf.  Never both, and never a third choice.
 *
 * @@@ Is the ability to hande a pool==NULL still useful?
 */
static char const *
ringPoolGetName(RingPool *pool, RingName *name, PGPSize *lenp)
{
	int i;
	MemPool cut;
	PGPVirtMask mask;
	RingFile *file, *file2;
	FilePos const *pos;
	char *str;
	PGPSize len, len1;

	*lenp = name->len;

	/* If we already have it, boom. */
	if (NAMEISCACHED(name))
		return name->name.ptr;

	/* If we weren't given a pool, we can't fetch it */
	if (!pool)
		return NULL;

	pgpVirtMaskInit (pool, &mask);

	/* find highest-priority fetchable file */
	file = ringBestFile(pool, (union RingObject *)name, 0);
	pgpAssert(file);
	pgpAssert(file->f ||
			  pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask));

	pos = ringFilePos((union RingObject *)name, file);
	pgpAssert(pos);

	/* If it's in memory, that was fast - set cached if it wasn't already*/
	if (pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask)) {
		pgpAssert(pos->fpos == name->len);
		pgpAssert(ringHashBuf((PGPByte *)pos->ptr.buf, name->len) ==
		       name->name.hash);
		NAMESETCACHED(name);
		NAMESETFILEMASK(name, MEMRINGBIT);
		pgpVirtMaskCleanup (pool, &mask);
		return name->name.ptr = (char *)pos->ptr.buf;
	}

	/* Allocate cache space for it */
	/* Dummy loop to break out of */
	do {
		/* Try the preferred cache */
		file2 = file;
		cut = file2->strings;	/* Remember cutback position */
		str = (char *)memPoolAlloc(&file2->strings, name->len + 1, 1);
		if (str)
			break;
		/* Try the pktbuf */
		str = ringReserve(pool, name->len + 1);
		if (str) {
			file2 = NULL;
			pool->pktbuflen = name->len;
			break;
		}
		/* Okay, desperation time - look for any cache */
		pgpVirtMaskCopy (pool, &name->mask, &mask);
		pgpVirtMaskAND (pool, &pool->filemask, &mask);
		pgpVirtMaskANDNOT (pool, &pool->memringmask, &mask);
		pos = &name->pos;
		for (;;) {
			i = pgpVirtMaskLSBit(&mask);
			pgpAssert(i >= 0);
			pgpAssert(pool->files[i]->f);
			file2 = pool->files[i];
			cut = file2->strings;
			str = (char *)memPoolAlloc(&file2->strings,
			                           name->len + 1, 1);
			if (str)
				break;
			pgpVirtMaskClearBit (pool, &mask, i);
			if (pgpVirtMaskIsEmpty (&mask)) {
				ringAllocErr(pool);
				pgpVirtMaskCleanup (pool, &mask);
				return NULL;
			}
			pos = pos->ptr.next;
		}
	} while (0);	/* Dummy loop to break out of */

	/* Okay, we got buffer space... get the packet */

	if (pgpFileSeek(file->f, pos->fpos, SEEK_SET) != 0) {
		i = kPGPError_FileOpFailed;
		goto error;
	}
	i = pktByteGet(file->f, &len, &len1, (PGPSize *)NULL);
	if (i < 0)
		goto error;
	if (PKTBYTE_TYPE(i) !=
					(NAMEISATTR(name) ? PKTBYTE_ATTRIBUTE : PKTBYTE_NAME)
			|| len != name->len)
		goto badpkt;

	i = pktBodyRead(str, len, len1, file->f);
	str[len] = '\0';			/* null char beyond end of name */
	if ((size_t)i != (size_t)len) {
		i = pgpFileError(file->f) ? kPGPError_ReadFailed :
					    kPGPError_EOF;
		goto error;
	}

	/* Double-check that we got the right thing. */
	if (ringHashBuf((PGPByte *)str, len) != name->name.hash)
		goto badpkt;

	/* Success at last! */
	if (file2) {
		/* It's cached in file2 - set flags appropriately */
		NAMESETCACHED(name);
		NAMESETFILEMASK(name, pgpVirtMaskLSBit(&file2->set.mask));
		name->name.ptr = str;
	}
	pgpVirtMaskCleanup (pool, &mask);
	return str;
	
badpkt:
	i = kPGPError_BadPacket;
error:
	if (file2)
		memPoolCutBack(&file2->strings, &cut);
	ringErr(file, pos->fpos, (PGPError)i);
	pgpVirtMaskCleanup (pool, &mask);
	return NULL;
}


void const *
ringFetchObject(RingSet const *set, union RingObject *obj, PGPSize *lenp)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -