pgprngpriv.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 902 行 · 第 1/2 页
C
902 行
pgpAssert(*objp);
objp = &(*objp)->g.next;
}
*objp = obj->g.next;
ringFreeObject(pool, obj);
}
/*
* Rebuild the pool's hash table from scratch,
* inserting all keys and subkeys.
*/
void
ringPoolHash(struct RingPool *pool)
{
union RingObject *key, *subkey;
int i;
for (i = 0; i < 256; i++)
pool->hashtable[i] = NULL;
for (key = pool->keys; key; key = key->g.next) {
pgpAssert(OBJISKEY(key));
RINGPOOLHASHKEY(pool, key);
for (subkey = key->g.down; subkey; subkey = subkey->g.next) {
if (OBJISKEY(subkey))
RINGPOOLHASHKEY(pool, subkey);
}
}
}
/*
* Find a key given a keyID.
*
* ViaCrypt added pkalgs 2 and 3 which are limited RSA, but doesn't
* completely distinguish beterrn them, so this doesn't either. Sigh.
*/
union RingObject *
ringPoolFindKey(struct RingPool const *pool, byte pkalg, byte const keyID[8])
{
struct RingKey *key;
if ((pkalg | 1) == 3)
pkalg = 1;
for (key = pool->hashtable[keyID[0]]; key; key = key->util) {
if (memcmp(keyID, key->keyID, 8) == 0) {
if (pkalg == key->pkalg)
break;
/* Cope with ViaCrypt's things */
if (pkalg == 1 && (key->pkalg | 1) == 3)
break;
}
}
return (union RingObject *)key;
}
/*
* Ensure that each key's list of the signatures by it is
* valid. This also establishes the extra invariant (used in
* pgpRngMnt.c) that all signatures by one key on another object
* are adjacent on that key's sigsby list.
*/
void
ringPoolListSigsBy(struct RingPool *pool)
{
union RingObject *key, *n, *s;
/* Initialize sigsby lists to null */
for (key = pool->keys; key; key = key->g.next) {
pgpAssert(OBJISKEY(key));
key->k.sigsby = NULL;
}
/* Install every sig on a sigsby list */
for (key = pool->keys; key; key = key->g.next) {
for (n = key->k.down; n; n = n->g.next) {
if (OBJISSIG(n)) {
n->s.nextby = (struct RingSig *) n->s.by->k.sigsby;
n->s.by->k.sigsby = n;
} else for (s = n->g.down; s; s = s->g.next) {
if (OBJISSIG(s)) {
s->s.nextby = (struct RingSig *) s->s.by->k.sigsby;
s->s.by->k.sigsby = s;
}
}
}
}
}
/*
* Return the mask of RingFiles that are "better" (higher priority
* for fetching) than *any* home of the specified object.
*/
static ringmask
ringObjBetters(union RingObject const *obj, struct RingPool const *pool)
{
ringmask better = pool->filemask;
ringmask mask = obj->g.mask & pool->filemask;
int bit;
pgpAssert(mask);
do {
bit = ringLsBitFind(mask);
better &= pool->files[bit].higherpri;
} while (mask &= mask-1);
return better;
}
/*
* Find the best Secret which is a descendant of the given key,
* in the given set.
*/
union RingObject *
ringBestSec(struct RingSet const *set, union RingObject const *key)
{
ringmask mask = set->mask;
ringmask better = (ringmask)~(ringmask)0;
union RingObject *obj, *best = 0;
pgpAssert(OBJISKEY(key));
for (obj = key->g.down; obj; obj = obj->g.next) {
if (obj->g.mask & better
&& obj->g.mask & mask
&& OBJISSEC(obj)) {
best = obj;
better = ringObjBetters(obj, set->pool);
}
}
return best;
}
/*
* Return TRUE if the specified subkey has a valid sig from the main key.
* Assumes subkey sigs are always tried, which should happen when they are
* created or added to the keyring. The only time this isn't true is when
* we are considering adding a key. We will give the sig the benefit of
* the doubt in that case as we aren't using it yet.
*/
int
ringSubkeyValid(struct RingSet const *set, union RingObject *subkey)
{
union RingObject *sig;
union RingObject *key;
pgpAssert(OBJISSUBKEY(subkey));
pgpAssert(subkey->g.mask & set->mask);
key = subkey->g.up;
pgpAssert(OBJISTOPKEY(key));
if (subkey->k.trust & (PGP_KEYTRUSTF_REVOKED | PGP_KEYTRUSTF_EXPIRED))
return 0;
for (sig = subkey->g.down; sig; sig = sig->g.next) {
if (OBJISSIG(sig) && (sig->g.mask & set->mask) &&
ringSigMaker(set, sig, set)==key &&
ringSigType(set, sig) == PGP_SIGTYPE_KEY_SUBKEY) {
if (!ringSigTried(set, sig))
return 1; /* could check it here... */
if (ringSigChecked(set, sig))
return 1;
}
}
return 0;
}
void
ringPurgeCachedName(struct RingName *name, ringmask mask)
{
pgpAssert(NAMEISNAME(name));
if (NAMEISCACHED(name) && (mask >> (name->flags & NAMEF_FILEMASK)) & 1)
{
/* Replace buffer with a hash of it */
name->name.hash = ringHashBuf((byte const *)name->name.ptr,
name->len);
NAMECLEARCACHED(name);
}
}
/*
* This function is called by the MemPool code when it runs out of memory.
* We try to free up more memory by purging the uids from cache.
* Returns zero if it was unable to make more memory available;
* non-zero if it might be useful to retry an allocation.
*/
static int
ringPurgeUidCache(void *arg)
{
struct RingPool *pool = (struct RingPool *)arg;
union RingObject *k, *n;
int i;
/*
* Quick check to see if we can do anything. As memory gets
* full, the full walk needed to clear the cache gets expensive,
* so avoid it unless it does some good.
*/
i = 0;
while (memPoolIsEmpty(&pool->files[i].strings)) {
if (++i == MEMRINGBIT) /* Last resort: try garbage collect */
return ringGarbageCollect(pool);
}
/*
* Okay, we have something cached to free; replace all the
* pointers to non-MEMRINGBIT cached named with hashes
* of the names and then deallocate the names.
*/
for (k = pool->keys; k; k = k->g.next) {
pgpAssert(OBJISKEY(k));
for (n = k->g.down; n; n = n->g.next) {
if (OBJISNAME(n))
ringPurgeCachedName(&n->n,
(ringmask)~MEMRINGMASK);
}
}
/* Free the pools */
for (i = 0; i < MEMRINGBIT; i++)
memPoolEmpty(&pool->files[i].strings);
return 1; /* We freed some memory */
}
/*
* Helper function for ringPoolInit.
*/
static void
ringFileInit(struct RingPool *pool, struct RingFile *file)
{
file->set.pool = pool;
file->set.next = NULL;
file->set.mask = 0;
file->set.type = RINGSET_FILE;
file->f = NULL;
file->destructor = NULL;
file->arg = NULL;
memPoolInit(&file->strings);
memPoolInit(&file->troublepool);
memPoolSetPurge(&file->troublepool, ringPurgeUidCache, (void *)pool);
file->trouble = NULL;
file->troubletail = &file->trouble;
memPoolInit(&file->fpos);
memPoolSetPurge(&file->fpos, ringPurgeUidCache, (void *)pool);
file->freepos = NULL;
file->higherpri = 0;
file->flags = 0;
}
/*
* Initialize a newly allocated struct RingPool.
*/
void
ringPoolInit(struct RingPool *pool, struct PgpEnv const *env)
{
int i;
memPoolInit(&pool->structs);
memPoolSetPurge(&pool->structs, ringPurgeUidCache, (void *)pool);
pool->keys = NULL;
for (i = 0; i < RINGTYPE_MAX; i++)
pool->freeobjs[i] = NULL;
pool->sets = NULL;
pool->freesets = NULL;
pool->freeiter = NULL;
pool->pktbuf = NULL;
pool->pktbuflen = 0;
pool->pktbufalloc = 0;
/* Reserve last keyring for memory */
pool->allocmask = MEMRINGMASK;
pool->filemask = MEMRINGMASK;
pool->flags = 0;
#if PGPTRUSTMODEL==0
if (env) {
i = pgpenvGetInt(env, PGPENV_CERTDEPTH, NULL, NULL);
pool->certdepth = i;
i = pgpenvGetInt(env, PGPENV_MARGINALS, NULL, NULL);
pool->num_marginals = (i < 0) ? 0 : (i > 255) ? 255 : i;
i = pgpenvGetInt(env, PGPENV_COMPLETES, NULL, NULL);
pool->num_completes = (i < 0) ? 0 : (i > 255) ? 255 : i;
} else {
pool->certdepth = 4;
pool->num_marginals = 2;
pool->num_completes = 1;
}
#else
if (env) {
i = pgpenvGetInt(env, PGPENV_CERTDEPTH, NULL, NULL);
pool->certdepth = i;
/* Compute values for new trust settings */
i = pgpenvGetInt(env, PGPENV_TRUSTED, NULL, NULL);
pool->threshold = (i > PGP_NEWTRUST_INFINITE) ?
PGP_NEWTRUST_INFINITE : (i < 0) ? 0 : i;
i = pgpenvGetInt(env, PGPENV_MARGINALS, NULL, NULL);
i = (i < 1) ? 0 : (pool->threshold+i-1)/i;
pool->marginalconfidence = i;
i = pgpenvGetInt(env, PGPENV_COMPLETES, NULL, NULL);
i = (i < 1) ? 0 : (pool->threshold+i-1)/i;
pool->completeconfidence = i;
} else {
pool->certdepth = 4;
pool->threshold = 3*PGP_TRUST_DECADE_INTERNAL;
pool->marginalconfidence = 3*PGP_TRUST_DECADE_INTERNAL/2;
pool->completeconfidence = 3*PGP_TRUST_DECADE_INTERNAL;
}
#if PGPTRUSTMODEL==2
memPoolInit (&pool->pathpool);
pool->paths = NULL;
pool->pathlists = NULL;
#endif
#endif
ringPoolClearError(pool);
for (i = 0; i < 256; i++)
pool->hashtable[i] = NULL;
for (i = 0; i < RINGMASKBITS; i++) {
ringFileInit(pool, &pool->files[i]);
pool->files[i].set.mask = (ringmask)1 << i;
}
/* Also purge strings cache if needed to create a new object. */
memPoolSetPurge(&pool->files[MEMRINGBIT].strings,
ringPurgeUidCache, (void *)pool);
}
/*
* Deallocate everything in sight on a RingPool preparatory to
* deallocating it.
*/
void
ringPoolFini(struct RingPool *pool)
{
struct RingFile *file;
int bit;
/*
* Do this first part, until the destructors are called,
* "properly" so structures aren't dangling undefined.
*/
for (bit = 0; bit <= MEMRINGBIT; bit++)
ringFilePurgeTrouble(&pool->files[bit]);
for (bit = 0; bit <= MEMRINGBIT; bit++) {
file = &pool->files[bit];
if (file->destructor) {
file->destructor(file, file->f, file->arg);
file->destructor = NULL;
}
}
memPoolEmpty(&pool->structs);
#if PGPTRUSTMODEL==2
memPoolEmpty (&pool->pathpool);
#endif
for (bit = 0; bit <= MEMRINGBIT; bit++) {
file = &pool->files[bit];
memPoolEmpty(&file->strings);
memPoolEmpty(&file->fpos);
}
pgpMemFree(pool->pktbuf);
/* Nuke the lot */
memset(pool, 0, sizeof(*pool));
}
/*
* This is defined as a macro.
*
* void
* ringFileMarkDirty(struct RingFile *file)
* {
* file->flags |= RINGFILEF_DIRTY;
* }
*/
/*
* Mark every file under a given mask as dirty.
*/
void
ringPoolMarkDirty(struct RingPool *pool, ringmask mask)
{
mask &= pool->filemask;
while (mask) {
ringFileMarkDirty(pool->files + ringLsBitFind(mask));
mask &= mask-1;
}
}
void
ringPoolMarkTrustChanged(struct RingPool *pool, ringmask mask)
{
mask &= pool->filemask;
while (mask) {
pool->files[ringLsBitFind(mask)].flags |=
RINGFILEF_TRUSTCHANGED;
mask &= mask-1;
}
}
/*
* Do a fingerprint20 (SHA-1) hash on the specified buffer, which
* should be key data. We prefix it with the type and length bytes
* for compatibility with key signature hashes (once they become SHA
* based). Return the number of bytes in the hash, or negative on
* error.
*/
int
pgpFingerprint20HashBuf(byte const *buf, size_t len, byte *hash)
{
struct PgpHash const *h;
struct PgpHashContext *hc;
byte tmpbuf[3];
byte const *p;
h = pgpHashByNumber (PGP_HASH_SHA);
if (!h)
return PGPERR_BAD_HASHNUM;
hc = pgpHashCreate(h);
if (!hc)
return PGPERR_NOMEM;
/* We use this format even for subkeys */
tmpbuf[0] = PKTBYTE_BUILD(PKTBYTE_PUBKEY, 1);
tmpbuf[1] = (byte)(len>>8);
tmpbuf[2] = (byte)len;
pgpHashUpdate(hc, tmpbuf, 3);
pgpHashUpdate(hc, buf, len);
p = pgpHashFinal(hc);
memcpy(hash, p, h->hashsize);
pgpHashDestroy(hc);
return h->hashsize;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?