pgprngmnt.c

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

C
2,034
字号
	for (n = k->down; n; n = n->g.next) {
#if BESTVALID
		if (OBJISNAME(n) && (n->g.mask & mask) &&
		n->n.valid >= bestvalid)
#else
		if (OBJISNAME(n) && (n->g.mask & mask))
#endif
		{
			cur = n->n.confidence;
			if (cur == PGP_NEWTRUST_INFINITE)
				cur = n->n.valid;
			else if (cur == PGP_NEWTRUST_UNDEFINED)
				cur = 0;
			else
				cur = mergetrust(cur << TRUST_CERTSHIFT,
				n->n.valid);
#if BESTVALID
			if (n->n.valid > bestvalid ||
			 		(n->n.valid == bestvalid && cur > best)) {
			 		best = cur;
			 			bestvalid = n->n.valid;
			 	}
	#else
			if (cur > best)
				best = cur;
#endif
		}
	}
	return best;
}

word16
ringKeyCalcTrust(struct RingSet const *set, union RingObject *key)
{
	word16 trust;
	pgpAssert(OBJISKEY(key));
	pgpAssert(set->mask & key->g.mask);
	trust = calctrust (&key->k, set->mask);
	if (trust == PGP_TRUST_INFINITE)
	return trust;
	return trust;
}
	
#endif /* PGPTRUSTMODEL>0 */


#if PGPTRUSTMODEL==1

/*
* Add confidence to the name signed by the given sig, and if the name
* has confidence and the key has not already been processed, add it
* to the list. Return the expanded list.
*
* TODO: Do something sensible with signatures on keys.
*/
static struct RingKey *
mntDoSig(struct RingSig const *sig, struct RingKey *list,
	word16 confidence, word32 const timenow, int const level,
	int pass2)
{
	union RingObject *name, *key;
	int i;
	byte sigtype;

	pgpAssert(mntSigIsValid(timenow, sig->tstamp, sig->validity));

	/* Okay, it hasn't expired, check that we have a name signature */
	name = sig->up;

	if (!OBJISNAME(name)) {
		/* @@@ Do anything here with signatures on keys? */
		return list;
	}

	sigtype = sig->type & 0xF0;
	if (sigtype != PGP_SIGTYPE_KEY_GENERIC)
		return list;
	key = name->n.up;
	pgpAssert(OBJISKEY(key));
	/* Do not add confidence from a key to itself */
	if (key == sig->by)
		return list;
		/*
	* There are two passes: first we add trust from keys at one level
	* to keys on the next level, then we add trust from keys at
	* that level to each other. Pass2 is a flag controlling which
	* we do.
	* Oh, names which we have no confidence in as introducers
	* get their certainty added from all levels, since they cannot
	* participate in cycles. This is done during pass 1.
	* So, during pass 1:
	* - Ignore names on keys that we have already recorded that are
	* at levels less than the current one.
	* And during pass 2:
	* - Ignore names other than ones at the specified level on keys
	* that *are* trusted. (On keys that are not will get added
	* next iteration).
		*/
	i = NAMELEVEL(&name->n);
	if (!pass2) {
		/* Pass 1 */
		if (!i)
			NAMESETLEVEL(&name->n, level);
		else if (i < level && key->g.flags & KEYF_TRUSTED)
			return list;
	} else {
		/* Pass 2 */
		if (i != level || !(key->g.flags & KEYF_TRUSTED))
			return list;
	}

	/* Okay, now add the confidence if needed. Do special
	checks for infinite confidence and validity. */

	if (confidence == PGP_TRUST_INFINITE)
		name->n.valid = PGP_TRUST_INFINITE;
	else if (name->n.valid != PGP_TRUST_INFINITE) {
		name->n.valid += confidence;
		/*
		* Saturate on overflow. 65535 is reserved for "perfect".
		* 65534 is 2.5164 * 10^-26, 2^-85.
		*/
		if (name->n.valid + 1 <= confidence)
			name->n.valid = (word16) PGP_TRUST_MAX;
			}

			/*
			* Don't add keys to the list if:
			* - Already on list
			* - Key is revoked (confidence is zero then)
			* - Key is expired (same as revoked)
			* - Name has no confidence
			* Currently, disabled keys *are* allowed on the list,
			* to participate in trust transactions. Disabling only
		* affects key selection. This is PGP 2.x compatible.
			*
			* Once a key is on the list, only one more round of adding
			* certainty to its names is possible, since two rounds could
			* create cycles that correcting for is difficult. Thus,
			* we want to avoid putting things on the list unnecessarily,
			* but prefer to weed out everything possible now.
			*/
	if (key->g.flags & KEYF_TRUSTED	/* Already listed? */
	|| key->k.trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED)
/*	|| key->k.trust & PGP_KEYTRUSTF_DISABLED */ /*PGP 2.x compatible*/
	|| !name->n.confidence)
		return list;
	key->k.util = (struct RingKey *)list;
	key->g.flags |= KEYF_TRUSTED;
	return &key->k;
}

/*
* Add confidence to each name signed by a valid signature on
* the "sigs" list. If the trust passes "thresh", add the resultant
* key to the list. Return the expanded list.
*
* Signatures that are expired or have been superseded are weeded out.
* Note that a postdated signature does not supersede one dated yesterday!
*/
static struct RingKey *
mntWalkSigList(struct RingSig const *sigs, struct RingKey *list,
	word16 confidence, ringmask const mask, word32 const timenow,
	int const level, int pass2)
{
	struct RingSig const *cur;

	while (sigs) {
		/* Find the first valid checked signature under the mask. */
		if (!(sigs->trust & PGP_SIGTRUSTF_CHECKED)
		|| !(sigs->mask & mask)
		|| !mntSigIsValid(timenow, sigs->tstamp, sigs->validity))
		{
			sigs = sigs->nextby;
			continue;
		}
		/* The first candidate signature */
		cur = sigs;

			/*
		* Search all other signatures by this key on the same object
		* for the most recent valid signature, which is the only
		* one which is accorded any weight. We use the fact that
		* after ringPoolListSigsBy places all signatures on
		* the same object together in the sigsby list.
				*/
		while ((sigs = sigs->nextby) != NULL && sigs->up == cur->up)
			 {
			 		/*
			 		* So now that the signature at the front of the sigs
			 		* list is on the same thing as "cusrig", consider
			 		* replacing cur, if the new signature is is
			 		* checked good, valid, under the right mask, and
			 		* more recent than cur.
			 		*
			 		*/
			if (sigs->trust & PGP_SIGTRUSTF_CHECKED
			&& sigs->mask & mask
			&& cur->tstamp < sigs->tstamp
			&& mntSigIsValid(timenow, sigs->tstamp,
			 		sigs->validity))
				cur = sigs;
			 }

		/* Do the trust computations on the resultant signature. */
		list = mntDoSig(cur, list, confidence, timenow, level, pass2);
	}
	return list;
}

/*
* Walk a list of keys (linked through the util field), adding the
* appropriate trust values to the names the key has signed.
*/
	static struct RingKey const *
	mntList(struct RingKey const *list, ringmask const mask,
		word32 const timenow, unsigned const level)
	{
		struct RingKey *newlist;
		struct RingKey *cur;
		word16 confidence;

		/* Do first pass, adding trust from old list to new things */
		for (newlist = NULL; list; list = list->util) {
			 pgpAssert(list->flags & KEYF_TRUSTED);
			 confidence = calctrust(list, mask);
			 if (!confidence)
			 	continue;
		newlist = mntWalkSigList(&list->sigsby->s, newlist, confidence,
		mask, timenow, level, 0);
			}
			/*
			* Do second pass, adding trust from new list to itself.
			* The overall confidence for each key must be calculated
			* before the second pass begins to avoid artificially high
			* confidence values caused by loops. Using a new field
			* 'list->confidence' increases the size of each key object
			* by 2 bytes (@@@ can we avoid this?)
			*/
	for (cur = newlist; cur; cur = cur->util) {
		pgpAssert(cur->flags & KEYF_TRUSTED);
		cur->confidence = calctrust(cur, mask);
	}
	for (cur = newlist; cur; cur = cur->util) {
		if (!cur->confidence)
			continue;
		newlist = mntWalkSigList(&cur->sigsby->s, newlist,
				cur->confidence,
				mask, timenow, level, 1);
		}

return newlist;
}

#endif /* PGPTRUSTMODEL==1 */

#if SORT_NAMES
/*
* Return 1 if n1 should be listed before n2; 0 if they're
* equivalent and the relative order should be unchanged, and -1
* if it should be the other way around.
*
* All non-names should be before all names; non-names are left in
* their original order.
*/
static int
mntCompareNames(union RingObject const *n1, union RingObject const *n2,
	word32 const timenow)
{
	word32 t1, t2;
	union RingObject const *sig;
	int i;

	/* Test 0: non-names always come first */
	if (!OBJISNAME(n1))
		return OBJISNAME(n2) ? 1 : 0;
	if (!OBJISNAME(n2))
		return -1;

	/* Test 1: more trusted */
	i = (n1->n.trust & PGP_NAMETRUST_MASK) -
		(n2->n.trust & PGP_NAMETRUST_MASK);
	if (i)
		return i > 0 ? 1 : -1;

	/* Test 2: more recent self-signature */
	t1 = 0;
	for (sig = n1->g.down; sig; sig = sig->g.next) {
		if (!OBJISSIG(sig) || sig->s.by != n1->g.up)
			continue;	 /* Not a self-sig */
		if ((sig->s.trust & PGP_SIGTRUSTF_CHECKED) == 0)
			continue;	 /* Not valid */
		if (sig->s.tstamp <= t1)
			continue;	 /* Too old */
		if (timenow > sig->s.tstamp &&
			(unsigned)((timenow-sig->s.tstamp) / 86400) > sig->s.validity-1u)
			continue;	 /* expired */
		t1 = sig->s.tstamp;
	}

	t2 = 0;
	for (sig = n2->g.down; sig; sig = sig->g.next) {
		if (!OBJISSIG(sig) || sig->s.by != n1->g.up)
			continue;	 /* Not a self-sig */
		if ((sig->s.trust & PGP_SIGTRUSTF_CHECKED) == 0)
			continue;	 /* Not valid */
		if (sig->s.tstamp <= t2)	
			continue;	 /* Too old */
		if (timenow > sig->s.tstamp &&
			(unsigned)((timenow-sig->s.tstamp) / 86400) > sig->s.validity-1u)
			continue;	 /* expired */
		t2 = sig->s.tstamp;
	}
	if (t1 != t2)
		return (t1 > t2 ? 1 : -1);

#if PGPTRUSTMODEL==0
	/* Test 3: lower certification depth */
	if (NAMELEVEL(&n1->n) != NAMELEVEL(&n2->n)) {
		return ((unsigned)NAMELEVEL(&n1->n) - 1u <
		(unsigned)NAMELEVEL(&n2->n) - 1u) ? 1 : -1;
	}

	/* Test 4: more trust accumulated */
	if (n1->n.trustval != n2->n.trustval)
		return n1->n.trustval > n2->n.trustval ? 1 : -1;
#else
	/* Test 3: More certainty */
	if (n1->n.valid != n2->n.valid)
		return n1->n.valid > n2->n.valid ? 1 : -1;

	/* Test 4: lower certification depth */
	if (NAMELEVEL(&n1->n) != NAMELEVEL(&n2->n)) {
		return ((unsigned)NAMELEVEL(&n1->n) - 1u <
		(unsigned)NAMELEVEL(&n2->n) - 1u) ? 1 : -1;
	}
#endif

	/* Okay, give up - declare 'em equal */
	return 0;
}

/*
* Sort the names in the given list according to a "goodness" measure.
* This may result in some keyrings getting dirtied. The mask of such
* keyrings is returned.
*
* This is a selection sort, not wonderfully efficient, but n^2 is okay
* for the small n we have here (5 names on a key is pretty unusual!),
* and it makes figuring out which keyrings need dirtying much easier.
*
* The technique is perhaps not entirely obvious, so I'll explain it.
* Selection sort involves searching the unsorted list for the object (name)
* that should go first (referred to as the best element in the code), and
* then removing it and placing it at the end of the (initially empty)
* sorted new list. We keep track of the union of the masks of the objects
* that the best object skips in front of. When we reach the end of the
* unsorted list, and the best pointer (and the bestmask) is known for
* sure, all keyrings which the best object is in and have been skipped
* over (i.e. bestmask & best->mask) are dirty.
*/
static ringmask
mntSortNameList(union RingObject **objp, word32 const timenow)
{
	union RingObject *newhead, **newtail;
	union RingObject *cur, **curp;
	union RingObject *best, **bestp;
	ringmask curmask, bestmask;
	ringmask dirtymask = 0;

	newtail = &newhead;

	/* Loop until unsorted list is empty */
	while (*objp) {
		/* Default best is head of list */
		bestp = objp;
		best = *bestp;
		bestmask = 0;

		/* Search rest of list for a better name */
		curp = &best->g.next;
		curmask = best->g.mask;
		while ((cur = *curp) != 0) {
			if (mntCompareNames(best, cur, timenow) < 0) {
				bestp = curp;
				best = cur;
				bestmask = curmask;
			}
			curmask |= cur->g.mask;
			curp = &cur->g.next;
		}

		*bestp = best->g.next;
		dirtymask |= bestmask & best->g.mask;
		*newtail = best;
		newtail = &best->g.next;
	}
	*objp = newhead;
	*newtail = NULL;
	return dirtymask;
}

/*
* Sort the names of each key under the given mask with the mntSortNameList
* function. The mask applies only to the keys; all names are sorted,
* even

⌨️ 快捷键说明

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