pgprngmnt.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 2,034 行 · 第 1/5 页
C
2,034 行
/*
* Add "inc" trust to the name signed by the given sig.
* If the trust passes "thresh", mark the name with the level
* and add the key that owns it to the list. Return the expanded list.
*
* TODO: Do something sensible with signatures on keys.
*/
static struct RingKey const *
mntDoSig(struct RingSig const *sig, struct RingKey const *list,
int const inc, int const thresh, word32 const timenow, int const level)
{
union RingObject *name, *key;
byte sigtype;
(void)timenow; /* Avoid warning */
pgpAssert(mntSigIsValid(timenow, sig->tstamp, sig->validity));
name = sig->up;
if (!OBJISNAME(name)) {
/* @@@ do anything with sigs on keys? */
return list;
}
#if 0
/* Ignore self-signature */
key = name->n.up;
pgpAssert(OBJISKEY(key));
if (key == sig->by)
return list;
#endif
sigtype = sig->type & 0xF0;
if (sigtype != PGP_SIGTYPE_KEY_GENERIC)
return list;
#if PRINT_PROGRESS
printf(" Trust %d/%d -> %d/%d on name ",
name->n.trustval, thresh,
name->trustval + inc, thresh);
(void)ringTtyPutString(name->name, name->len, -1u, stdout, '"', '"');
putchar('\n');
#endif
name->n.trustval += inc;
/*
* If we are not yet at the valid level or have already
* marked this name as validated, bail out.
*/
if (name->n.trustval < thresh || NAMELEVEL(&name->n))
return list;
/* Passed threshold - label with certification level. */
NAMESETLEVEL(&name->n, level);
key = name->n.up;
pgpAssert(OBJISKEY(key));
if (key->g.flags & KEYF_TRUSTED || /* Already listed? */
key->k.trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED))
return list;
#if PRINT_PROGRESS
ringKeyIDprint(stdout,
" Potential introducer: first userID trust >= 1 on keyID ",
key->keyID);
#endif
key->k.util = (struct RingKey *)list;
key->g.flags |= KEYF_TRUSTED;
return &key->k;
}
/*
* Look for other keys signed by the grandparent of sig which have the same
* name. Propagate the same trust to those names. (Don't do it if they
* have a sig by the same signing key.) The reasoning is that the same
* person owns both keys, he has the same name, so sigs on the first name
* can be treated as though they are on the other name. This will facilitate
* moving to a new key from an old one.
*
* One issue not dealt with here is that if the grandparent key here is also
* a trusted introducer, trust will move to the destination key in two ways:
* here, by direct "pair propagation" from signatures on that key's names
* which match the names here; and also by normal trust propagation due to
* the signature. This could end up counting some trust twice, although
* in this trust model it doesn't look like it introduces any significant
* weaknesses.
*/
static struct RingKey const *
mntDoMatchingNames(struct RingSig const *sig, struct RingKey const *list,
RingSet const *set, int const inc, int const thresh, word32 const timenow,
int const level)
{
RingObject *name; /* Name which sig is on */
RingObject *key; /* Key which name is on */
RingObject *propsig; /* All sigs by key */
RingObject *propname; /* Name which propsig is on */
RingObject *propkey; /* Key which propname is on */
RingObject *namesig; /* All sigs on propname */
byte sigtype;
byte selfsigfound;
ringmask const mask = set->mask;
pgpAssert(mntSigIsValid(timenow, sig->tstamp, sig->validity));
/* Ignore sigs not on names */
name = sig->up;
if (!OBJISNAME(name))
return list;
/* Ignore self signatures, invalid keys, and keys which don't sign */
key = name->n.up;
pgpAssert(OBJISKEY(key));
if (key == sig->by)
return list;
if (key->k.trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED))
return list;
/* Ignore funny kinds of sigantures */
sigtype = sig->type & 0xF0;
if (sigtype != PGP_SIGTYPE_KEY_GENERIC)
return list;
/*
* As a short-term security precaution, only propagate for fully valid
* names. The problem is that otherwise, someone could have two keys,
* A and B, which both are marginally valid. If both A and B sign key
* C which has the same name, the marginally valid signatures combine
* to give full validity to C. We have a solution to this but it is
* complex. For now we will only do propagation from names which are
* fully valid, which will mean that only fully valid keys get their
* trust propagated to matching names.
*/
if (!NAMELEVEL(&name->n))
return list;
/* Look for other keys with same name */
for (propsig = key->k.sigsby; propsig;
propsig = (RingObject *)propsig->s.nextby) {
if (!(propsig->g.mask & mask))
continue;
propname = propsig->s.up;
/* Ignore sigs not on names */
if (!OBJISNAME(propname))
continue;
propkey = propname->n.up;
/* Ignore nonkeys(?) or self sigs */
if (!OBJISKEY(propkey) || propkey == key)
continue;
/* Make sure signature is valid */
if (!(propsig->s.trust & PGP_SIGTRUSTF_CHECKED)
|| !(propsig->s.mask & mask)
|| !mntSigIsValid(timenow, propsig->s.tstamp, propsig->s.validity))
continue;
if ((propsig->s.type & 0xF0) != PGP_SIGTYPE_KEY_GENERIC)
continue;
/* See if names match */
if (ringNamesDiffer (set, name, propname))
continue;
/* Skip if name already has a sig from our signer */
/* Also, this must be the newest sig by us */
/* Also, it must have a self signature */
selfsigfound = 0;
for (namesig=propname->n.down; namesig; namesig=namesig->s.next) {
if (!OBJISSIG(namesig) || !(namesig->g.mask & mask))
continue;
if (namesig->s.by == sig->by)
break; /* Break out with nonnull namesig on match */
if (namesig != propsig && namesig->s.by == key
&& namesig->s.tstamp >= propsig->s.tstamp)
break; /* Break outwith nonnull namesig if not newest */
/* Check for valid self signature */
if (namesig->s.by == propkey
&& (namesig->s.trust & PGP_SIGTRUSTF_CHECKED)
&& (namesig->s.mask & mask)
&& mntSigIsValid(timenow, namesig->s.tstamp,
namesig->s.validity)) {
selfsigfound = 1;
}
}
/* If namesig is non-null it had a matching sig, skip this name */
/* Also if there was no self signature */
if (namesig || !selfsigfound)
continue;
/* OK, we have a name suitable for propagating trust to */
list = mntDoSig(&propsig->s, list, inc, thresh, timenow, level);
}
return list;
}
/*
* Add "inc" trust 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 const *
mntWalkSigList(struct RingSig const *sigs, struct RingKey const *list,
RingSet const *set, int const inc, int const thresh, word32 const timenow,
int const level)
{
struct RingSig const *cur;
ringmask const mask = set->mask;
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
*/
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, inc, thresh, timenow, level);
/* Propagate sig info also to linked keys with matching names */
list = mntDoMatchingNames(cur, list, set, inc, thresh, timenow, level);
}
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, RingSet const *set, int const add[8],
int const threshold, word32 const timenow, unsigned const level)
{
struct RingKey const *newlist;
int trustinc;
for (newlist = 0; list; list = list->util) {
pgpAssert(list->flags & KEYF_TRUSTED);
trustinc = add[list->trust & PGP_KEYTRUST_MASK];
#if PRINT_PROGRESS
printf(, "Adding %d/%d trust from ", trustinc, threshold);
ringKeyPrint(stdout, (struct RingPool *)0, "", list);
#endif
#if 0
/*
* @@@ PGP 2.x allows disabled keys to participate in
* trust computation. Should this be added?
*/
if (list->trust & (PGP_KEYTRUSTF_DISABLED))
continue;
#endif
if (trustinc <= 0)
continue;
newlist = mntWalkSigList(&list->sigsby->s, newlist, set, trustinc,
threshold, timenow, level);
}
return newlist;
}
#else /* PGPTRUSTMODEL>0 */
/*
* This finds the combined trust value given two trusts which
* are arranged in series. Trust values are actually the
* scaled negative logarithms of *distrust*, so assuming
* independent failures, two signatures in parallel have a
* distrust which is the product of the input distrusts, and
* we only have to add the trust values. But when they're
* in series, we want to multiply the *trusts*, and it gets hairier...
* This is a quick and dirty brute-force-and-ignorance approach.
* I know of better solutions, but haven't had time to do the
* necessary numerical analysis.
*
* @@@ Optimize this code
*
* Given t1 = log(p1)/k and t2 = log(p2)/k, where p1 and p2 are
* probabilities that are bounded between 0 < p1,p2 <= 1, find
* t3 = log(1-(1-p1)*(1-p2))/k
* = log(1-(1-exp(t1*k))*(1-exp(t2*k)))/k.
* = log(p1 + p2 - p1*p2)
* = log(exp(t1*k) + exp(t2*k) - exp(t1*k)*exp(t2*k))/k
* k is chosen to make the logs come out right,
* so that an increment of TRUST_DECADE corresponds to 1/10.
* I.e. exp(TRUST_DECADE*k) = 1/10
* => TRUST_DECADE*k = log(1/10)
* => k = -log(10)/TRUST_DECADE;
* Well, actually there's an additional factor of TRUST_CERTSHIFT
* thrown in there, a factor of 64 which allows probabilities down to
* 10^-25 and a granularity of +/-0.09% in trust values.
* Note that p1+p2-p1*p2 = p1 + p2*(1-p1) >= p1, so the output
* probability is always greater than either of the input probabilities,
* so t3 is always less than t1 or t2. Thus, the computation can't
* overflow.
*
* I'd prefer to somehow evaluate it directly in log form, using
* something like Zech's log function to evaluate it.
* H'm... an alternate evaluation technique...
* p1 * (1 + p2/p1(1-p1))
* = p1 * (1 + p2*(1/p1-1))
* Choose p1 as the larger of the two... does this lead to anything?
* Yes. Two tables of size 771 (= ceil(log(2)*40*64)) will allow you
* to evaluate (1/p1-1) directly, guaranteed to round down, and then
* I think something similar will do for (t+1). For the (1/p1-1)
* evaluation, do the entries for p1 from 1 to 1/2 directly, and
* past that, the value of (1/p1-1) differes from the value of
* 1/p1 by at most 771. Record in another table the values at
* which the delta changes, do a binary search, and use the index as
* the delta.
*/
#include <math.h>
#ifndef M_LN10
#define M_LN10 2.30258509299404568402 /* ln(10) */
#endif
static word16
mergetrust(word16 t1, word16 t2)
{
static double const k = -M_LN10 / PGP_TRUST_DECADE;
double p, q;
/* Saturate at infinity */
if (t1 == (word16) PGP_TRUST_INFINITE)
return t2;
if (t2 == (word16) PGP_TRUST_INFINITE)
return t1;
p = exp(t1*k);
q = exp(t2*k);
/* Round down for conservative estimate */
return (word16)floor(log(p + q - p*q)/k);
}
/*
* Compute the trust value associated with a key. This is the
* weight given to signatures made by that key. The decision is based
* on the validity of the key's name (how sure are we that the name
* belongs to that key) and confidence (how much do we trust the
* named individual). The product of those two gives the trust in
* the key as a whole.
*
* If the key is a buckstop key, ignore the validity and just take the
* confidence as-is.
*
* If there are multiple names on a key, compute the trust for each and
* use the maximum.
*
* BESTVALID alternate algorithm
*
* If BESTVALID if set, then the overall trust in a key is determined
* from the name with the highest validity. In the case of a tie,
* then the best validity*confidence is taken. Thus, overall trust
* is computed from the name this key is most likely to belong to.
*/
#ifndef BESTVALID
#define BESTVALID 1
#endif
static word16
calctrust(struct RingKey const *k, ringmask mask)
{
union RingObject const *n;
word16 cur, best = 0;
#if BESTVALID
word16 bestvalid = 0;
#endif
pgpAssert(KEYISKEY(k));
/* For BUCKSTOP keys, validity and confidence are infinite.
Revoked or expired keys have no validity or confidence. */
if (k->trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED))
return 0;
if (k->trust & PGP_KEYTRUSTF_BUCKSTOP)
return PGP_TRUST_INFINITE;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?