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