pgprngmnt.c

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

C
2,034
字号

/* Prototype */
static PathList **
ringFindPathsKey (RingObject *start, PathList **ppath,
	Path *predh, Path **predt, unsigned depth,
unsigned maxdepth, RingSet const *set, word32 timenow, RingPool *pool);

/* Helper routines for ringFindPathsName */

/* Return the newest valid signature by the given key on the given name */
static RingObject *
ringNewestValidSig (RingObject *name, RingObject *key, unsigned depth,
	RingSet const *set, word32 timenow)
{
	RingObject		*bestsig = NULL,
					*sig;
	ringmask const	mask = set->mask;

	pgpAssert (OBJISNAME(name));
	pgpAssert (OBJISKEY(key));

	for (sig = name->g.down; sig; sig = sig->g.next) {
		if (OBJISSIG(sig)
			&& (sig->s.trust & PGP_SIGTRUSTF_CHECKED)
			&& ((sig->g.mask & mask) || depth==1)
			&& sig->s.by == key
			&& mntSigIsValid(timenow, sig->s.tstamp, sig->s.validity)) {
			/* Good sig by key, see if it is newer than bestsig */
			if (!bestsig
				|| bestsig->s.tstamp < sig->s.tstamp) {
				bestsig = sig;
			}
		}
	}
	return bestsig;
}

/*
* Return true if there is a signature by the key on an earlier sibling
* of this name. This alerts us to a condition which could cause duplicate
* paths, which will waste resources.
*/
static int
ringEarlierValidSig (RingObject *name, RingObject *key, RingSet const *set,
	word32 timenow)
{
	RingObject		*parent,
					*sibname,
					*sig;
	ringmask const	mask = set->mask;

	pgpAssert (OBJISNAME(name));
	pgpAssert (OBJISKEY(key));

	parent = name->g.up;
	pgpAssert (OBJISKEY(parent));

	for (sibname=parent->g.down; sibname!=name; sibname=sibname->g.next) {
		if (!OBJISNAME(sibname)
			|| !(sibname->g.mask & mask))
			continue;
		for (sig=sibname->g.down; sig; sig=sig->g.next) {
			if (OBJISSIG(sig)
			&& (sig->s.trust & PGP_SIGTRUSTF_CHECKED)
			&& (sig->g.mask & mask)
			&& sig->s.by == key
			&& mntSigIsValid(timenow, sig->s.tstamp, sig->s.validity)) {
				/* Have an earlier signature we are looking for */
				return TRUE;
			}
		}
	}
	return FALSE;
}

/*
* See if the specified key is in the special "pairing" relationship with
* the specified name. We are called with key signing name. The main point
* is whether key has a name which matches. If so, we return that name.
* It is also necessary that name be self-signed, so we will check for that
* here. The signing key must be valid as well.
*/
static RingObject *
ringPairedName (RingObject *name, RingObject *key, RingSet const *set)
{
	RingObject			*keyname;	 /* Names on key */
	RingObject			*namekey;	 /* Key parent of name */
	RingObject			*namesig;	 /* Sigs on name */
	byte const			*smatchname; /* Actual name of *name */
	byte const			*sname;		/* Actual name of *keyname */
	unsigned			lmatchname; /* Length of smatchname */
	unsigned			lname;		 /* Length of sname */
	ringmask const		mask = set->mask;
	
	pgpAssert (OBJISKEY(key));
	pgpAssert (OBJISNAME(name));

	/* Check for key validity */
	if (key->k.trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED))
		return NULL;
	
	/* Check that name is self-signed */
	namekey = name->n.up;
	pgpAssert (OBJISKEY(namekey));
	for (namesig = name->n.down; namesig; namesig = namesig->g.next) {
		if (!OBJISSIG(namesig))
			continue;
		/* XXX Should check expiration */
		if ((namesig->s.trust & PGP_SIGTRUSTF_CHECKED)
			&& (namesig->g.mask & mask)
			&& (namesig->s.type & 0xF0) == PGP_SIGTYPE_KEY_GENERIC) {
			break;				/* Exit with namesig nonnull on success */
		}
	}
	if (!namesig)	 		 	/* NULL namesig means no self sig */
		return NULL;
		
	/* Get userid string of name */
	smatchname = (byte const *)ringFetchObject(set, name, &lmatchname);

	/* See if any names on keyname match */
	for (keyname = key->k.down; keyname; keyname = keyname->n.next) {
		if (!OBJISNAME(keyname))
			continue;
		sname = (byte const *)ringFetchObject(set, name, &lname);
		if (lname == lmatchname && !memcmp (sname, smatchname, lname)) {
			/* Have a matching name! */
			return keyname;
		}
	}
	return NULL;
}


/*
* Find all the paths from the starting name back to an axiomatically
* trusted key.
* pred holds the path which leads to the starting key from some target.
* lastseg points at the last segment of the path, which already has
* the key this name is on as the dest. We just have to fill it in
* and recurse, or check for buckstop keys.
*
* We reject paths which are to keys which have
* already been processed as signing this key. This can happen
* if there are two names on a key, both signed by another key. Otherwise
* these would be treated as two different paths, but they
* end up being identical. The Maurer algorithm correctly accounts for this,
* but it is a waste. What we do is, for each signature, we check
* all our earlier name siblings and see if they have a signature from the
* same key. If so we skip this sig.
*
* Returns	tail pointer for updated PathList
*
* name		 starting name object for search backwards through web of trust
* ppath	 tail pointer of PathList to add our new paths to
* newseg	pointer to the last segment of the Path we will add to
* predh	 pointer to the (head of the) Path we will add to
* predt	 tail pointer to the Path we will add to (&newseg->tail)
* depth	 length of path so far, counting newseg (e.g. 1 at outer level)
* maxdepth	maximum length of paths we allow
* set		 ringset for trusted keys
* timenow	current timestamp
* pool		 ringpool to use for memory allocations
* skipsigs list of signatures, chained by next, not to follow key of
*
*/
static PathList **
ringFindPathsName (RingObject *name, PathList **ppath, Path *newseg,
	Path *predh, Path **predt, unsigned depth,
unsigned maxdepth, RingSet const *set, word32 timenow, RingPool *pool,
	RingObject *skipsigs)
{
	RingObject *sig,
	*sigkey,
				*pairedname,
				*ssig;
	ringmask const	mask = set->mask;

	for (sig = name->g.down; sig; sig = sig->g.next) {
		if (!OBJISSIG(sig))
			continue;
		/* Skip if invalid sig */
		if (!(sig->s.trust & PGP_SIGTRUSTF_CHECKED)
			|| (!(sig->g.mask & mask) && depth>1)
			|| !mntSigIsValid(timenow, sig->s.tstamp, sig->s.validity)
			|| (sig->s.type & 0xF0) != PGP_SIGTYPE_KEY_GENERIC)
			continue;
		/* Skip if signing key not in signer set */
		sigkey = sig->s.by;
		if (!(sigkey->g.mask & mask))
			continue;
		/* Skip if there is a newer valid sig by the same key */
		if (ringNewestValidSig (name, sigkey, depth, set, timenow) != sig)
			continue;
		/* Skip if we have already done this key on an earlier sibling */
		if (depth>1 && ringEarlierValidSig (name, sigkey, set, timenow))
			continue;
		/*
		* Skip if signing key is in skipsigs list. This is for the "paired
		* keys" feature.
		*/
		for (ssig = skipsigs; ssig; ssig = ssig->g.next) {
			if (OBJISSIG(ssig) && sigkey == ssig->s.by)
				break;			/* Exit from loop with ssig nonnull on match */
		}
		if (ssig)		 		 /* Non-null ssig means it was on skip list */
			continue;

		/* OK, investigate this signer further */
		newseg->src = sigkey;
		if (sigkey->k.trust & PGP_KEYTRUSTF_BUCKSTOP
			&& !(sigkey->k.trust & (PGP_KEYTRUSTF_REVOKED |
											PGP_KEYTRUSTF_EXPIRED))
			/*&& !(key->k.trust & PGP_KEYTRUSTF_DISABLED)*/) {
			/* Found a path */
			newseg->confidence = 1.0;
			ppath = pathListAddPathClone (ppath, predh, pool);
			if (!ppath) {
				/* Out of memory */
				return NULL;
			}
		} else if (depth < maxdepth &&
				!LOOKINGAT(&sigkey->k) &&
				(newseg->confidence =
					pathKeyConfidence(sigkey, set)) != 0) {
			/* Recurse */
			ppath = ringFindPathsKey (sigkey, ppath, predh, predt,
					depth+1, maxdepth, set, timenow, pool);
			if (!ppath) {
				/* Out of memory */
				return NULL;
			}
#if 0
/* This code is not yet tested */
		} else if (depth < maxdepth &&
				!LOOKINGAT(&sigkey->k) &&
				(pairedname = ringPairedName(name, sigkey, set)) != NULL) {
			 		/*
			* We have a signature by a sibling key, one which matches our
			* name. Recurse from that name. The resulting path element
			* will have as source, signer of that paired name, and as
			* destination, this key. Even though there is no "actual"
			* signature in such a form, there is an implied signature.
			* We won't increment depth in this case.
			* Here we use the skipsigs feature - we don't want to follow
			* any sigs from our pair which we are also following here.
			* This is the only place it is used (at this writing!).
			 		*/
			ppath = ringFindPathsName (pairedname, ppath, newseg, predh, predt,
				depth, maxdepth, set, timenow, pool, name->g.down);
			if (!ppath) {
				/* Out of memory */
				return NULL;
			}
#endif
		}
	}
	return ppath;
}


/*
* Find all the paths from the starting key back to an axiomatically
* trusted key.
*
* Returns	tail pointer for updated PathList
*
* start	 starting key object for search backwards through web of trust
* ppath	 tail pointer of PathList to add our new paths to
* predh	 pointer to the (head of the) Path we will add to
* predt	 tail pointer to the Path we will add to
* depth	 length of path, counting segment we will add (newseg, below)
* maxdepth	maximum length of paths we allow
* set		 ringset for trusted keys
* timenow	current timestamp
* pool		 ringpool to use for memory allocations
*
*/
static PathList **
ringFindPathsKey (RingObject *start, PathList **ppath,
	Path *predh, Path **predt, unsigned depth,
	unsigned maxdepth, RingSet const *set, word32 timenow, RingPool *pool)
{
	RingObject *name;
	Path *newseg;
	Path **newpredt;

	/* It's a key but not axiomatic */
	pgpAssert (OBJISKEY(start));
	pgpAssert (!(start->k.trust & PGP_KEYTRUSTF_BUCKSTOP));

	newseg = pathAlloc(pool);
	if (!newseg) {
		/* Out of memory */
		return NULL;
	}
	newseg->dest = start;
	newseg->next = NULL;
	newpredt = pathAddSeg (predt, newseg);
	SETLOOKINGAT(&start->k);
	for (name = start->g.down; name; name = name->g.next) {
		if (!OBJISNAME(name))
			continue;
		if (name->n.confidence == 0 ||
			name->n.confidence == PGP_NEWTRUST_UNDEFINED)
			continue;
		ppath = ringFindPathsName (name, ppath, newseg, predh, newpredt,
			depth, maxdepth, set, timenow, pool, NULL);
		if (!ppath)				/* out of memory */
			break;
	}
	CLEARLOOKINGAT(&start->k);
	pathFree (newseg, pool);
	*predt = NULL;
	return ppath;
}



/*
* Find all paths backwards from the specified target name to some key
* which is axiomatically trusted.
*
* Returns	tail pointer for new PathList
*
* name		 starting name object for search backwards through web of trust
* ppath	 address of PathList pointer we set to point to head of PathList
* maxdepth	maximum length of paths we allow
* set		 ringset for trusted keys
* timenow	current timestamp
* pool		 ringpool to use for memory allocations
*
*/
static PathList **
ringFindPathsBack (RingObject *name, PathList **ppath, unsigned maxdepth,
	RingSet const *set, word32 const timenow, RingPool *pool)
{
Path *phead = NULL,
**ptail = &phead;
	RingObject *key;
	ringmask const	mask = set->mask;

	pgpAssert (OBJISNAME(name));
	pgpAssert (name->g.mask & mask);
	key = name->g.up;
	phead = pathAlloc(pool);
	if (!phead)
		return NULL;
	SETLOOKINGAT(&key->k);			/* avoid loops involving target */
	phead->dest = key;
	phead->src = NULL;
	phead->confidence = 0.;
	phead->next = NULL;
	ptail = &phead->next;
	ppath = ringFindPathsName (name, ppath, phead, phead, ptail, 1, maxdepth,
		set, timenow, pool, NULL);
	CLEARLOOKINGAT(&key->k);
	pathFree (phead, pool);
	return ppath;
}

/*
* Create a copy of the given ringSet, but containing only keys which have
* at least one name with defined confidence.
*/
static struct RingSet *
ringSetConfidentSet (struct RingSet const *set)
{
	struct RingSet		*trustedset;
	struct RingIterator	*iter;

	trustedset = ringSetCreate (ringSetPool (set));
	if (!trustedset)
		return 0;
	iter = ringIterCreate (set);
	if (!iter) {
		ringSetDestroy (trustedset);
		return 0;
	}
	ringSetAddSet (trustedset, set);
	while (ringIterNextObject (iter, 1)) {
		int goodconf = 0;		 		 /* True if key has a conf. name */
		while (ringIterNextObject (iter, 2)) {
			union RingObject *nameobj;
			nameobj = ringIterCurrentObject (iter, 2);
			if (!OBJISNAME(nameobj))
				continue;
			/* Remove names with undefined or zero confidence */
			if (nameobj->n.confidence == PGP_NEWTRUST_UNDEFINED ||
				nameobj->n.confidence == 0) {
				ringSetRemObject (trustedset, nameobj);
			} else {
				goodconf = 1;
			}
		}
		if (!goodconf) {
			ringSetRemObject (trustedset, ringIterCurrentObject (iter, 1));
		}
	}
	ringIterDestroy (iter);
	ringSetFreeze (trustedset);
	return trustedset;
}

#endif /* PGPTRUSTMODEL==2 */

#if PGPTRUSTMODEL==0

⌨️ 快捷键说明

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