pgprngpriv.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 902 行 · 第 1/2 页

C
902
字号
				 pgpAssert(*objp);
				 objp = &(*objp)->g.next;
			}
			*objp = obj->g.next;
			ringFreeObject(pool, obj);
	}

/*
* Rebuild the pool's hash table from scratch,
* inserting all keys and subkeys.
*/
void
ringPoolHash(struct RingPool *pool)
{
union RingObject *key, *subkey;
int i;

for (i = 0; i < 256; i++)
	pool->hashtable[i] = NULL;

for (key = pool->keys; key; key = key->g.next) {
			pgpAssert(OBJISKEY(key));
			RINGPOOLHASHKEY(pool, key);
			for (subkey = key->g.down; subkey; subkey = subkey->g.next) {
					if (OBJISKEY(subkey))
							RINGPOOLHASHKEY(pool, subkey);
			}
	}
}

/*
* Find a key given a keyID.
*
* ViaCrypt added pkalgs 2 and 3 which are limited RSA, but doesn't
* completely distinguish beterrn them, so this doesn't either. Sigh.
*/
union RingObject *
ringPoolFindKey(struct RingPool const *pool, byte pkalg, byte const keyID[8])
{
			struct RingKey *key;

			if ((pkalg | 1) == 3)
				 pkalg = 1;
			for (key = pool->hashtable[keyID[0]]; key; key = key->util) {
					if (memcmp(keyID, key->keyID, 8) == 0) {
							if (pkalg == key->pkalg)
								break;
							/* Cope with ViaCrypt's things */
							if (pkalg == 1 && (key->pkalg | 1) == 3)
								break;
					}
		}

			return (union RingObject *)key;
	}


/*
* Ensure that each key's list of the signatures by it is
* valid. This also establishes the extra invariant (used in
* pgpRngMnt.c) that all signatures by one key on another object
* are adjacent on that key's sigsby list.
*/
void
ringPoolListSigsBy(struct RingPool *pool)
	{
			union RingObject *key, *n, *s;

			/* Initialize sigsby lists to null */
			for (key = pool->keys; key; key = key->g.next) {
				 pgpAssert(OBJISKEY(key));
				 key->k.sigsby = NULL;
	}

			/* Install every sig on a sigsby list */
			for (key = pool->keys; key; key = key->g.next) {
			for (n = key->k.down; n; n = n->g.next) {
			if (OBJISSIG(n)) {
					n->s.nextby = (struct RingSig *) n->s.by->k.sigsby;
					n->s.by->k.sigsby = n;
					} else for (s = n->g.down; s; s = s->g.next) {
					if (OBJISSIG(s)) {
					s->s.nextby = (struct RingSig *) s->s.by->k.sigsby;
									s->s.by->k.sigsby = s;
							}
						}
				}
			}
	}


/*
* Return the mask of RingFiles that are "better" (higher priority
* for fetching) than *any* home of the specified object.
*/
static ringmask
ringObjBetters(union RingObject const *obj, struct RingPool const *pool)
	{
			ringmask better = pool->filemask;
			ringmask mask = obj->g.mask & pool->filemask;
			int bit;

			pgpAssert(mask);

			do {
				 bit = ringLsBitFind(mask);
				 better &= pool->files[bit].higherpri;
			} while (mask &= mask-1);

			return better;
}


/*
* Find the best Secret which is a descendant of the given key,
* in the given set.
*/
union RingObject *
ringBestSec(struct RingSet const *set, union RingObject const *key)
	{
			ringmask mask = set->mask;
			ringmask better = (ringmask)~(ringmask)0;
			union RingObject *obj, *best = 0;

			pgpAssert(OBJISKEY(key));
			for (obj = key->g.down; obj; obj = obj->g.next) {
				 if (obj->g.mask & better
				 && obj->g.mask & mask
				 && OBJISSEC(obj)) {
				 		best = obj;
				 		better = ringObjBetters(obj, set->pool);
				 }
			}
			return best;

}

/*
* Return TRUE if the specified subkey has a valid sig from the main key.
* Assumes subkey sigs are always tried, which should happen when they are
* created or added to the keyring. The only time this isn't true is when
* we are considering adding a key. We will give the sig the benefit of
* the doubt in that case as we aren't using it yet.
*/
int
ringSubkeyValid(struct RingSet const *set, union RingObject *subkey)
	{
			union RingObject *sig;
			union RingObject *key;

			pgpAssert(OBJISSUBKEY(subkey));
			pgpAssert(subkey->g.mask & set->mask);
			key = subkey->g.up;
			pgpAssert(OBJISTOPKEY(key));

			if (subkey->k.trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED))
			return 0;
			for (sig = subkey->g.down; sig; sig = sig->g.next) {
					if (OBJISSIG(sig) && (sig->g.mask & set->mask) &&
					ringSigMaker(set, sig, set)==key &&
					ringSigType(set, sig) == PGP_SIGTYPE_KEY_SUBKEY) {
							if (!ringSigTried(set, sig))
								 return 1; /* could check it here... */
							if (ringSigChecked(set, sig))
									return 1;
					}
			}
			return 0;
	}

	void
ringPurgeCachedName(struct RingName *name, ringmask mask)
	{
			pgpAssert(NAMEISNAME(name));

			if (NAMEISCACHED(name) && (mask >> (name->flags & NAMEF_FILEMASK)) & 1)
			{
					/* Replace buffer with a hash of it */
					name->name.hash = ringHashBuf((byte const *)name->name.ptr,
							 		name->len);
					NAMECLEARCACHED(name);
			}
	}

/*
* This function is called by the MemPool code when it runs out of memory.
* We try to free up more memory by purging the uids from cache.
* Returns zero if it was unable to make more memory available;
* non-zero if it might be useful to retry an allocation.
*/
static int
ringPurgeUidCache(void *arg)
	{
			struct RingPool *pool = (struct RingPool *)arg;
			union RingObject *k, *n;
			int i;

		/*
			* Quick check to see if we can do anything. As memory gets
			* full, the full walk needed to clear the cache gets expensive,
			* so avoid it unless it does some good.
			*/
			i = 0;
			while (memPoolIsEmpty(&pool->files[i].strings)) {
				 if (++i == MEMRINGBIT) /* Last resort: try garbage collect */
				 	return ringGarbageCollect(pool);
			}

			/*
			* Okay, we have something cached to free; replace all the
			* pointers to non-MEMRINGBIT cached named with hashes
			* of the names and then deallocate the names.
			*/
			for (k = pool->keys; k; k = k->g.next) {
					pgpAssert(OBJISKEY(k));
					for (n = k->g.down; n; n = n->g.next) {
							if (OBJISNAME(n))
									ringPurgeCachedName(&n->n,
									(ringmask)~MEMRINGMASK);
				}
		}

/* Free the pools */
for (i = 0; i < MEMRINGBIT; i++)
	memPoolEmpty(&pool->files[i].strings);

return 1;	/* We freed some memory */
}

/*
* Helper function for ringPoolInit.
*/
static void
ringFileInit(struct RingPool *pool, struct RingFile *file)
	{
			file->set.pool = pool;
			file->set.next = NULL;
			file->set.mask = 0;
			file->set.type = RINGSET_FILE;

			file->f = NULL;
			file->destructor = NULL;
			file->arg = NULL;
			memPoolInit(&file->strings);
			memPoolInit(&file->troublepool);
			memPoolSetPurge(&file->troublepool, ringPurgeUidCache, (void *)pool);
			file->trouble = NULL;
			file->troubletail = &file->trouble;
			memPoolInit(&file->fpos);
			memPoolSetPurge(&file->fpos, ringPurgeUidCache, (void *)pool);
			file->freepos = NULL;
			file->higherpri = 0;
			file->flags = 0;
	}

/*
* Initialize a newly allocated struct RingPool.
*/
void
ringPoolInit(struct RingPool *pool, struct PgpEnv const *env)
	{
			int i;

memPoolInit(&pool->structs);
memPoolSetPurge(&pool->structs, ringPurgeUidCache, (void *)pool);
pool->keys = NULL;

for (i = 0; i < RINGTYPE_MAX; i++)
	pool->freeobjs[i] = NULL;
pool->sets = NULL;
pool->freesets = NULL;
pool->freeiter = NULL;

pool->pktbuf = NULL;
pool->pktbuflen = 0;
pool->pktbufalloc = 0;

/* Reserve last keyring for memory */
pool->allocmask = MEMRINGMASK;
pool->filemask = MEMRINGMASK;

pool->flags = 0;

#if PGPTRUSTMODEL==0
			if (env) {
					i = pgpenvGetInt(env, PGPENV_CERTDEPTH, NULL, NULL);
					pool->certdepth = i;
					i = pgpenvGetInt(env, PGPENV_MARGINALS, NULL, NULL);
					pool->num_marginals = (i < 0) ? 0 : (i > 255) ? 255 : i;
					i = pgpenvGetInt(env, PGPENV_COMPLETES, NULL, NULL);
					pool->num_completes = (i < 0) ? 0 : (i > 255) ? 255 : i;
			} else {
					pool->certdepth = 4;
					pool->num_marginals = 2;
					pool->num_completes = 1;
		}
	#else
			if (env) {
				 i = pgpenvGetInt(env, PGPENV_CERTDEPTH, NULL, NULL);
				 pool->certdepth = i;

				 /* Compute values for new trust settings */
				 i = pgpenvGetInt(env, PGPENV_TRUSTED, NULL, NULL);
					pool->threshold = (i > PGP_NEWTRUST_INFINITE) ?
						PGP_NEWTRUST_INFINITE : (i < 0) ? 0 : i;

					i = pgpenvGetInt(env, PGPENV_MARGINALS, NULL, NULL);
					i = (i < 1) ? 0 : (pool->threshold+i-1)/i;
					pool->marginalconfidence = i;
		
					i = pgpenvGetInt(env, PGPENV_COMPLETES, NULL, NULL);
					i = (i < 1) ? 0 : (pool->threshold+i-1)/i;
					pool->completeconfidence = i;
			} else {
					pool->certdepth = 4;
					pool->threshold = 3*PGP_TRUST_DECADE_INTERNAL;
					pool->marginalconfidence = 3*PGP_TRUST_DECADE_INTERNAL/2;
					pool->completeconfidence = 3*PGP_TRUST_DECADE_INTERNAL;
			}
#if PGPTRUSTMODEL==2
			memPoolInit (&pool->pathpool);
			pool->paths = NULL;
			pool->pathlists = NULL;
#endif
#endif
		
			ringPoolClearError(pool);

			for (i = 0; i < 256; i++)
				 pool->hashtable[i] = NULL;

			for (i = 0; i < RINGMASKBITS; i++) {
				 ringFileInit(pool, &pool->files[i]);
				 pool->files[i].set.mask = (ringmask)1 << i;
			}

			/* Also purge strings cache if needed to create a new object. */
			memPoolSetPurge(&pool->files[MEMRINGBIT].strings,
			ringPurgeUidCache, (void *)pool);
	}

/*
* Deallocate everything in sight on a RingPool preparatory to
* deallocating it.
*/
void
ringPoolFini(struct RingPool *pool)
{
			struct RingFile *file;
			int bit;
	
			/*
			* Do this first part, until the destructors are called,
			* "properly" so structures aren't dangling undefined.
			*/
			for (bit = 0; bit <= MEMRINGBIT; bit++)
				 ringFilePurgeTrouble(&pool->files[bit]);

			for (bit = 0; bit <= MEMRINGBIT; bit++) {
				 file = &pool->files[bit];
				 if (file->destructor) {
						file->destructor(file, file->f, file->arg);
						file->destructor = NULL;
					}
				}

				memPoolEmpty(&pool->structs);
#if PGPTRUSTMODEL==2
				memPoolEmpty (&pool->pathpool);
#endif

				for (bit = 0; bit <= MEMRINGBIT; bit++) {
					file = &pool->files[bit];
					memPoolEmpty(&file->strings);
					memPoolEmpty(&file->fpos);
				}

				pgpMemFree(pool->pktbuf);

				/* Nuke the lot */
				memset(pool, 0, sizeof(*pool));
}

/*
* This is defined as a macro.
*
* void
* ringFileMarkDirty(struct RingFile *file)
* {
*		file->flags |= RINGFILEF_DIRTY;
* }
*/

/*
* Mark every file under a given mask as dirty.
*/
void
ringPoolMarkDirty(struct RingPool *pool, ringmask mask)
{
				mask &= pool->filemask;
				while (mask) {
					ringFileMarkDirty(pool->files + ringLsBitFind(mask));
					mask &= mask-1;
			}
	}

void
ringPoolMarkTrustChanged(struct RingPool *pool, ringmask mask)
	{
				mask &= pool->filemask;
				while (mask) {
					pool->files[ringLsBitFind(mask)].flags |=
					RINGFILEF_TRUSTCHANGED;
					mask &= mask-1;
			}
	}


	/*
* Do a fingerprint20 (SHA-1) hash on the specified buffer, which
* should be key data. We prefix it with the type and length bytes
* for compatibility with key signature hashes (once they become SHA
* based). Return the number of bytes in the hash, or negative on
* error.
*/
int
pgpFingerprint20HashBuf(byte const *buf, size_t len, byte *hash)
	{
			struct PgpHash const *h;
			struct PgpHashContext *hc;
			byte tmpbuf[3];
			byte const *p;

			h = pgpHashByNumber (PGP_HASH_SHA);
			if (!h)
				 return PGPERR_BAD_HASHNUM;
			hc = pgpHashCreate(h);
			if (!hc)
				 return PGPERR_NOMEM;
			/* We use this format even for subkeys */
			tmpbuf[0] = PKTBYTE_BUILD(PKTBYTE_PUBKEY, 1);
			tmpbuf[1] = (byte)(len>>8);
			tmpbuf[2] = (byte)len;
			pgpHashUpdate(hc, tmpbuf, 3);
			pgpHashUpdate(hc, buf, len);
			p = pgpHashFinal(hc);
			memcpy(hash, p, h->hashsize);
			pgpHashDestroy(hc);
			return h->hashsize;
	}

⌨️ 快捷键说明

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