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

📄 pgptrustprop.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 5 页
字号:
 * or you set the confidence level on the new userid.  But this does not
 * happen because such userids are not included in the confident set.
 *
 * A worse problem is that Snidely could get Nell's userid on his key, get
 * some low-confidence signer to sign Nell, and get an even lower conf-
 * idence signer to sign his own.  Then we would use Nell's confidence
 * on Snidely's key, and if there were also a good signer on Snidely's userid,
 * which we hadn't run into yet, we would again count Snidely's signatures
 * too highly.
 *
 * So this suggests a safer heuristic which is to take either the lowest
 * confidence, or else perhaps to downgrade the confidence by the
 * validities.  However doing this if all the validities are accurate will
 * end up squaring them.  Maybe we could just downgrade by the relative
 * validities, best to worst...
 *
 * (For now we have an #if below to always use the lowest confidence)
 *
 * An idea suggested by Mark is to base the confidence on the particular
 * userid which is the next step in the path.  However this complicates the
 * union operation.
 * Either a path no longer has a well defined confidence, preventing
 * Maurer's algorithm from working, or else we have
 * to define a path as being from userid to userid, and if a key has two
 * userids (different email addresses, say, home and work) we would end up
 * counting its contribution to trust twice.  (This is essentially because
 * the assumption of independence fails spectacularly in this case!)
 *
 * Keep in mind that despite all these difficulties, if there is only one
 * userid then there is no problem!  We just use the confidence on that userid.
 */
static double
pathKeyConfidence (PGPKeyDBObj *key)
{
	PGPKeyDBObj *	userid;
	PGPKeyInfo *	kinfo;
	PGPUserIDInfo *	uinfo;
	double          minconfidence = 1.0,
	                confidence,
	                errorchance,
					useridconfidence,
					keyconfidence,
	                maxvalidconfidence = 0.;
	PGPUInt16       maxvalidity = 0;
	PGPBoolean		allvalid = TRUE;	/* True if all userids have validity */
	PGPBoolean		validuserid = FALSE;/* True if at least one valid userid */

	kinfo = pgpKeyToKeyInfo( key );
	for (userid = key->down; IsntNull(userid); userid = userid->next) {
		if( !pgpKeyDBObjIsReal( userid ) )
			continue;
		if( !OBJISUSERID(userid) )
			continue;
		uinfo = pgpUserIDToUserIDInfo( userid );
		if( uinfo->confidence == PGP_NEWTRUST_UNDEFINED )
			continue;
		validuserid = TRUE;
		errorchance =  pgpTrustToDouble (
		                    pgpTrustToIntern(uinfo->confidence));
		confidence = 1. - 1. / errorchance;
		if( confidence < minconfidence )
			minconfidence = confidence;
		if( uinfo->valid == 0 ) {
			allvalid = 0;
		} else if( uinfo->valid > maxvalidity ||
						(uinfo->valid == maxvalidity &&
						 confidence < maxvalidconfidence) ) {
			maxvalidity = uinfo->valid;
			maxvalidconfidence = confidence;
		}
	}
	/* If called with no valid userid, minconfidence is 0 */
	if( !validuserid )
		minconfidence = 0.;
	/*
	 * If all userids have known validity, use the most valid userid's
	 * confidence.  Else choose the lowest established confidence of
	 * any userid.
	 */
#if 0
/* Too risky to use this heuristic, just take minimum confidence */
	if( allvalid )
		useridconfidence = maxvalidconfidence;
	else
#endif
		useridconfidence = minconfidence;

	keyconfidence = 0.;
	if( kinfo->signedTrust != 0 ) {
		errorchance =  pgpTrustToDouble (
		                    pgpTrustToIntern(kinfo->signedTrust));
		keyconfidence = 1. - 1. / errorchance;
	}

	return pgpMax (keyconfidence, useridconfidence);
}

/* Prototype */
static PathList **
sFindPathsKey (PGPKeyDBObj *start, PathList **ppath,
	Path **predh, Path **predt, unsigned depth,
    unsigned maxdepth, PGPUInt32 timenow, PGPKeyDB *db, PGPKeyDB *altdb);

/* Helper routines for sFindPathsUserID */

/* Return the newest cryptograhpically-good signature by the given key on
 * the given userid.  This does not check for expirations or regexps.
 */
static PGPKeyDBObj *
sNewestGoodSig (PGPKeyDBObj *userid, PGPKeyDBObj *key)
{
	PGPKeyDBObj		*bestsig = NULL,
					*sig;
	PGPSigInfo		*sinfo;
	PGPSigInfo		*bestsiginfo = NULL;

	pgpAssert (OBJISUSERID(userid));
	pgpAssert (OBJISKEY(key));

	for (sig = userid->down; IsntNull(sig); sig = sig->next) {
		if( !pgpKeyDBObjIsReal( sig ) )
			continue;
		if( OBJISSIG(sig) ) {
			sinfo = pgpSigToSigInfo( sig );
			if ((sinfo->trust & PGP_SIGTRUSTF_CHECKED) && sinfo->by == key ) {
				/* Good sig by key, see if it is newer than bestsig */
				if( IsNull(bestsig)
					|| bestsiginfo->tstamp < sinfo->tstamp ) {
					bestsig = sig;
					bestsiginfo = sinfo;
				}
			}
		}
	}
	return bestsig;
}

/*
 * Return true if there is a signature by the key on an earlier sibling
 * of this userid.  This alerts us to a condition which could cause duplicate
 * paths, which will waste resources.  key and localkey will be distinct
 * in the case where signer is in an alternate keydb.  In that case localkey
 * is the key in the sig's db and key is the key in the alternate db.
 * Otherwise they are the same.
 */
static int
sEarlierValidSig (PGPKeyDBObj *userid, PGPKeyDBObj *key,
	PGPKeyDBObj *localkey, PGPUInt32 timenow)
{
	PGPKeyDBObj		*parent,
					*sibuserid,
					*sig;
	PGPSigInfo		*sinfo;

	pgpAssert (OBJISUSERID(userid));
	pgpAssert (OBJISKEY(key));
	pgpAssert (OBJISKEY(localkey));

	parent = userid->up;
	pgpAssert (OBJISKEY(parent));

	for (sibuserid=parent->down; sibuserid!=userid;
		 							sibuserid=sibuserid->next) {
		if( !pgpKeyDBObjIsReal( sibuserid ) )
			continue;
		if( !OBJISUSERID(sibuserid) )
			continue;
		for (sig=sibuserid->down; IsntNull(sig); sig=sig->next) {
			if( !pgpKeyDBObjIsReal( sig ) )
				continue;
			if( OBJISSIG(sig) ) {
				sinfo = pgpSigToSigInfo( sig );
				if( (sinfo->trust & PGP_SIGTRUSTF_CHECKED)
						&& !(sinfo->trust & PGP_SIGTRUSTF_REVOKEDBYCRL)
						&& sinfo->by == localkey
						&& mntSigOKWithRegexpOnSigner( sig, key )
						&& mntSigIsValidTime(timenow, sinfo->tstamp,
											 sinfo->sigvalidity) ) {
					/* 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 userid.  We are called with key signing userid.
 * The main point is whether key has a userid which matches.  If so,
 * we return that userid.  It is also necessary that userid be
 * self-signed, so we will check for that here.  The signing key must
 * be valid as well.
 */
static PGPKeyDBObj *
sPairedUserID (PGPKeyDBObj *userid, PGPKeyDBObj *key)
{
	PGPKeyDBObj			*keyuserid;	/* Userids on key */
	PGPKeyDBObj			*useridkey;	/* Key parent of userid */
	PGPKeyDBObj			*useridsig;	/* Sigs on userid */
	PGPByte const		*smatchuserid; /* Actual userid of *userid */
	PGPByte const		*suserid;		/* Actual userid of *keyuserid */
	PGPSize			 	lmatchuserid; /* Length of smatchuserid */
	PGPSize				luserid;		/* Length of suserid */
	PGPKeyInfo			*kinfo;
	PGPSigInfo			*uidsiginfo;
	
	pgpAssert (OBJISKEY(key));
	pgpAssert (OBJISUSERID(userid));

	kinfo = pgpKeyToKeyInfo( key );

	/* Check for key validity */
	if( kinfo->trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED) )
		return NULL;
	
	/* Check that userid is self-signed */
	useridkey = userid->up;
	pgpAssert (OBJISKEY(useridkey));
	for (useridsig = userid->down; IsntNull(useridsig);
		 							useridsig = useridsig->next) {
		if( !pgpKeyDBObjIsReal( useridsig ) )
			continue;
		if( !OBJISSIG(useridsig) )
			continue;
		uidsiginfo = pgpSigToSigInfo( useridsig );
		/* XXX Should check expiration */
		if( (uidsiginfo->trust & PGP_SIGTRUSTF_CHECKED)
			&& !(uidsiginfo->trust & PGP_SIGTRUSTF_REVOKEDBYCRL)
			&& (uidsiginfo->type & 0xF0) == PGP_SIGTYPE_KEY_GENERIC ) {
			break;				/* Exit with useridsig nonnull on success */
		}
	}
	if( IsNull(useridsig) )			/* NULL useridsig means no self sig */
		return NULL;
		
	/* Get userid string of userid */
	smatchuserid = pgpFetchObject( userid, &lmatchuserid );

	/* See if any userids on keyuserid match */
	for (keyuserid = key->down; IsntNull(keyuserid);
		 							keyuserid = keyuserid->next) {
		if( !pgpKeyDBObjIsReal( keyuserid ) )
			continue;
		if( !OBJISUSERID(keyuserid) )
			continue;
		suserid = pgpFetchObject( keyuserid, &luserid );
		if( luserid == lmatchuserid &&
			pgpMemoryEqual( suserid, smatchuserid, luserid ) ) {
			/* Have a matching userid! */
			return keyuserid;
		}
	}
	return NULL;
}


/*
 * Find all the paths from the starting userid 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 userid 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 userids 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 userid siblings and see if they have a signature from the
 * same key.  If so we skip this si
 *
 * Returns	tail pointer for updated PathList
 *
 * userid	starting userid 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 (&newseg->tail)
 * depth	length of path so far, counting newseg (e. 1 at outer level)
 * maxdepth	maximum length of paths we allow
 * timenow	current timestamp
 * db		PGPKeyDB to use for memory allocations
 * skipsigs list of signatures, chained by next, not to follow key of
 *
 */
static PathList **
sFindPathsUserID (PGPKeyDBObj *userid, PathList **ppath,
	Path **predh, Path **predt, unsigned depth,
    unsigned maxdepth, PGPUInt32 timenow, PGPKeyDB *db, PGPKeyDB *altdb,
	PGPKeyDBObj *skipsigs)
{
	PGPKeyDBObj     *sig,
	               *sigkey,
	               *localsigkey,
				   *paireduserid,
				   *ssig;
	Path		   *newseg;
	Path          **newpredt;
	double			confidence;
	PGPSigInfo	   *sinfo;
	PGPSigInfo	   *ssinfo;
	PGPKeyInfo	   *sigkeyinfo;
	int				tryalt;

	for( sig = userid->down; sig; sig = sig->next )
	{
		if( !pgpKeyDBObjIsReal( sig ) )
			continue;
		if( !OBJISSIG(sig) )
			continue;
		sinfo = pgpSigToSigInfo( sig );
		/* Skip if invalid sig */
		if( !(sinfo->trust & PGP_SIGTRUSTF_CHECKED)
			|| (sinfo->trust & PGP_SIGTRUSTF_REVOKEDBYCRL)
			|| !mntSigIsValidTime(timenow, sinfo->tstamp, sinfo->sigvalidity)
			|| (sinfo->type & 0xF0) != PGP_SIGTYPE_KEY_GENERIC )
			continue;
		/* Try tracing sigs back through altdb too */
		for( tryalt = 0;
			 tryalt <= (IsntNull(altdb) && (PGPPeekKeyDBObjKeyDB(sig)!=altdb));
			 ++tryalt )
		{
			if( tryalt == 0 )
			{
				sigkey = sinfo->by;
				localsigkey = sigkey;
			} else {
				PGPKeyID keyID;
				sigkey = NULL;
				if( IsntPGPError( pgpGetKeyIDOfCertifier( sig, &keyID) ) )
					pgpGetKeyByKeyID(altdb, &keyID, TRUE, FALSE, &sigkey );
				if( IsNull( sigkey ) )
					continue;
				localsigkey = sinfo->by;
			}
			/* Skip if signing key not trusted */
			if( !pgpKeyDBObjIsReal( sigkey ) )
				continue;
			if ( !sKeyHasConfidence (sigkey) )
				continue;
			if( !mntSigOKWithRegexpOnSigner( sig, sigkey ) )
				continue;

			/* Skip if there is a newer valid sig by the same key */
			if( sNewestGoodSig (userid, localsigkey) != sig )
				continue;
			/* Skip if we have already done this key on an earlier userid*/
			/* (I.e. sigkey signed more than one userid on this key) */
			if( depth>1 && sEarlierValidSig (userid, sigkey, localsigkey,
											 timenow) )
				continue;
			/*
			 * Skip if signing key is in skipsigs list.  This is for the
			 * "paired keys" feature.
			 */
			for (ssig = skipsigs; ssig; ssig = ssig->next) {
				if( !pgpKeyDBObjIsReal( ssig ) )
					continue;
				ssinfo = pgpSigToSigInfo( ssig );
				if( OBJISSIG(ssig) ) {
					if( localsigkey == ssinfo->by )
					{
						/* Exit from loop with ssig nonnull on match */
						break;
					}
				}
			}
			if( IsntNull(ssig) )
			{
				/* Non-null ssig means it was on skip list */
				continue;
			}

			/* OK, investigate this signer further */
			sigkeyinfo = pgpKeyToKeyInfo( sigkey );

			/* Don't count revoked or expired keys (new test!) */
			if( sigkeyinfo->trust & (PGP_KEYTRUSTF_REVOKED |
									 PGP_KEYTRUSTF_EXPIRED) )
				continue;

			if( (sigkeyinfo->trust & PGP_KEYTRUSTF_BUCKSTOP)
				/*&& !(sigkeyinfo->trust & PGP_KEYTRUSTF_DISABLED)*/ ) {
				/* Found a path */
				ppath = pathListAddPathClone (ppath, *predh, db);
				if( IsNull(ppath) ) {
					/* Out of memory */
					return NULL;
				}
			} else if( depth < maxdepth &&
					   !LOOKINGAT(sigkeyinfo) &&
					   (confidence = pathKeyConfidence(sigkey)) != 0 ) {
				/* Recurse */
				newseg = pathAlloc(db);
				if( IsNull(newseg) ) {
					/* Out of memory */
					return NULL;
				}
				newseg->dest = userid->up;
				newseg->src = sigkey;
				newseg->next = NULL;
				newseg->confidence = confidence;
				newpredt = pathAddSeg (predt, newseg);
				ppath = sFindPathsKey (sigkey, ppath, predh, newpredt,
						 depth+1, maxdepth, timenow, db, altdb);
				pathFree (newseg, db);
				*predt = NULL;
				if( IsNull(ppath) ) {
					/* Out of memory */
					return NULL;
				}
			} else if( depth < maxdepth &&
					   !LOOKINGAT(sigkeyinfo) &&
					   (paireduserid =
							sPairedUserID(userid, sigkey)) != NULL ) {
				/*
				 * We have a signature by a sibling key, one which matches our
				 * userid.  Recurse from that userid.  The resulting path element
				 * will have as source, signer of that paired userid, 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!).
				 */

⌨️ 快捷键说明

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