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 + -
显示快捷键?