📄 pgprngpriv.c
字号:
pgpIsRingSetMember(set, sig) &&
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(RingPool const *pool, RingName *name, PGPVirtMask *mask)
{
pgpAssert(NAMEISNAME(name));
if (NAMEISCACHED(name)) {
PGPInt32 bit = NAMEFILEMASK(name);
PGPVirtMask tmask;
pgpVirtMaskInit (pool, &tmask);
pgpVirtMaskSetBit (pool, &tmask, bit);
if (pgpVirtMaskIsOverlapping (&tmask, mask)) {
/* Replace buffer with a hash of it */
name->name.hash = ringHashBuf((PGPByte const *)name->name.ptr,
name->len);
NAMECLEARCACHED(name);
}
pgpVirtMaskCleanup (pool, &tmask);
}
}
/*
* 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)
{
RingPool *pool = (RingPool *)arg;
PGPVirtMask notmemringmask;
union RingObject *k, *n;
unsigned 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 = MEMRINGBIT+1;
while (IsntNull(pool->files[i]) &&
memPoolIsEmpty(&pool->files[i]->strings)) {
if (++i == pool->nfiles) /* 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.
*/
pgpVirtMaskInit (pool, ¬memringmask);
pgpVirtMaskCopy (pool, &pool->memringmask, ¬memringmask);
pgpVirtMaskNOT (pool, ¬memringmask, pool->nfiles);
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(pool, &n->n, ¬memringmask);
}
}
/* Free the pools */
for (i = 0; i < pool->nfiles; i++)
if (IsntNull(pool->files[i]))
memPoolEmpty(&pool->files[i]->strings);
pgpVirtMaskCleanup (pool, ¬memringmask);
return 1; /* We freed some memory */
}
/*
* Initialize a new RingFile structure. This does not set the mask field.
*/
static void
ringFileInit(
RingPool *pool, RingFile *file)
{
pgpAssert( pgpContextIsValid( pool->context ) );
file->set.pool = pool;
file->set.next = NULL;
pgpVirtMaskInit (pool, &file->set.mask);
file->set.type = RINGSET_FILE;
file->f = NULL;
file->destructor = NULL;
file->arg = NULL;
memPoolInit( pool->context, &file->strings);
memPoolInit( pool->context, &file->troublepool);
memPoolSetPurge(&file->troublepool, ringPurgeUidCache, (void *)pool);
file->trouble = NULL;
file->troubletail = &file->trouble;
memPoolInit( pool->context, &file->fpos);
memPoolSetPurge(&file->fpos, ringPurgeUidCache, (void *)pool);
file->freepos = NULL;
pgpVirtMaskInit (pool, &file->higherpri);
file->flags = 0;
}
/*
* Initialize pool->files to hold entries so we can access newfile
*/
void
ringFilesInit(RingPool *pool, PGPUInt32 newfile)
{
void *vfiles;
RingFile *file;
if (pool->nfiles < newfile+1) {
vfiles = pool->files;
pgpContextMemRealloc (pool->context, &vfiles,
(newfile+1) * sizeof(RingFile *), kPGPMemoryMgrFlags_Clear);
pool->files = (RingFile **) vfiles;
pool->nfiles = newfile+1;
}
/* Init newly allocated file struct */
pool->files[newfile] = (RingFile *)pgpContextMemAlloc (pool->context,
sizeof(RingFile), kPGPMemoryMgrFlags_Clear);
file = pool->files[newfile];
ringFileInit (pool, file);
pgpVirtMaskSetBit (pool, &file->set.mask, newfile);
}
/*
* Initialize a newly allocated RingPool.
*/
void
ringPoolInit(
PGPContextRef context,
RingPool * pool,
PGPEnv const * env)
{
int i;
pgpAssert( pgpContextIsValid( context ) );
pool->context = context;
memPoolInit( context, &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 first keyring for memory */
pgpVirtMaskInit (pool, &pool->memringmask);
pgpVirtMaskInit (pool, &pool->allocmask);
pgpVirtMaskInit (pool, &pool->filemask);
pgpVirtMaskSetBit (pool, &pool->memringmask, MEMRINGBIT);
pgpVirtMaskCopy (pool, &pool->memringmask, &pool->allocmask);
pgpVirtMaskCopy (pool, &pool->memringmask, &pool->filemask);
pool->flags = 0;
if (env) {
i = pgpenvGetInt(env, PGPENV_CERTDEPTH, NULL, NULL);
pool->certdepth = i;
/* Values used for TRUSTMODEL 0 */
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;
/* Values used for TRUSTMODEL 1 */
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->num_marginals = 2;
pool->num_completes = 1;
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 (context, &pool->pathpool);
pool->paths = NULL;
pool->pathlists = NULL;
#endif
ringPoolClearError(pool);
for (i = 0; i < 256; i++)
pool->hashtable[i] = NULL;
pool->nfiles = 0;
pool->files = NULL;
ringFilesInit (pool, MEMRINGBIT);
/* 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(RingPool *pool)
{
RingFile *file;
int bit;
/*
* Do this first part, until the destructors are called,
* "properly" so structures aren't dangling undefined.
*/
for (bit = 0; bit < (int)pool->nfiles; bit++)
if (IsntNull(pool->files[bit]))
ringFilePurgeTrouble(pool->files[bit]);
for (bit = 0; bit < (int)pool->nfiles; bit++) {
file = pool->files[bit];
if (file && 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 < (int)pool->nfiles; bit++) {
file = pool->files[bit];
if (IsntNull(file)) {
memPoolEmpty(&file->strings);
memPoolEmpty(&file->fpos);
pgpVirtMaskCleanup(pool, &file->set.mask);
pgpContextMemFree (pool->context, file);
pool->files[bit] = NULL;
}
}
if (IsntNull (pool->files)) {
pgpContextMemFree (pool->context, pool->files);
pool->files = NULL;
pool->nfiles = 0;
}
if( IsntNull( pool->pktbuf ) )
pgpContextMemFree( pool->context, pool->pktbuf);
pgpVirtMaskCleanup (pool, &pool->memringmask);
pgpVirtMaskCleanup (pool, &pool->allocmask);
pgpVirtMaskCleanup (pool, &pool->filemask);
/* Nuke the lot */
pgpClearMemory( pool, sizeof(*pool));
}
/*
* This is defined as a macro.
*
* void
* ringFileMarkDirty(RingFile *file)
* {
* file->flags |= RINGFILEF_DIRTY;
* }
*/
/*
* Mark every file under a given mask as dirty.
*/
void
ringPoolMarkDirty(RingPool *pool, PGPVirtMask *mask)
{
PGPVirtMask tmask;
pgpVirtMaskInit (pool, &tmask);
pgpVirtMaskCopy (pool, mask, &tmask);
pgpVirtMaskAND (pool, &pool->filemask, &tmask);
while (!pgpVirtMaskIsEmpty (&tmask)) {
PGPInt32 bit = pgpVirtMaskLSBit (&tmask);
pgpAssert (bit >= 0);
ringFileMarkDirty(pool->files[bit]);
pgpVirtMaskClearBit (pool, &tmask, bit);
}
pgpVirtMaskCleanup (pool, &tmask);
}
void
ringPoolMarkTrustChanged(RingPool *pool, PGPVirtMask *mask)
{
PGPVirtMask tmask;
pgpVirtMaskInit (pool, &tmask);
pgpVirtMaskCopy (pool, mask, &tmask);
pgpVirtMaskAND (pool, &pool->filemask, &tmask);
while (!pgpVirtMaskIsEmpty (&tmask)) {
PGPInt32 bit = pgpVirtMaskLSBit (&tmask);
pgpAssert (bit >= 0);
pool->files[bit]->flags |= RINGFILEF_TRUSTCHANGED;
pgpVirtMaskClearBit (pool, &tmask, bit);
}
pgpVirtMaskCleanup (pool, &tmask);
}
/*
* 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(PGPContextRef context, PGPByte const *buf, size_t len,
PGPByte *hash)
{
PGPHashVTBL const *h;
PGPHashContext *hc;
PGPByte tmpbuf[3];
PGPByte const *p;
PGPMemoryMgrRef memoryMgr = PGPGetContextMemoryMgr( context );
h = pgpHashByNumber (kPGPHashAlgorithm_SHA);
if (!h)
return kPGPError_BadHashNumber;
hc = pgpHashCreate( memoryMgr, h);
if (!hc)
return kPGPError_OutOfMemory;
/* We use this format even for subkeys */
tmpbuf[0] = PKTBYTE_BUILD(PKTBYTE_PUBKEY, 1);
tmpbuf[1] = (PGPByte)(len>>8);
tmpbuf[2] = (PGPByte)len;
PGPContinueHash(hc, tmpbuf, 3);
PGPContinueHash(hc, buf, len);
p = (PGPByte *) pgpHashFinal(hc);
memcpy(hash, p, h->hashsize);
PGPFreeHashContext(hc);
return h->hashsize;
}
/* Call this for sigs known to use a regexp, to return the regexp. Loads
* from disk if necessary. Returns NULL on error.
*/
void *
ringSigRegexp( RingSet const *set, RingObject *sig )
{
PGPByte *buf;
PGPSize len;
regexp *rexp;
char const *packet;
pgpAssert( OBJISSIG( sig ) );
pgpAssert( pgpIsRingSetMember(set, sig) );
pgpAssert( SIGUSESREGEXP( &sig->s ) );
if( !sig->s.regexp ) {
/* Here we must load the regexp */
buf = (PGPByte *)ringFetchObject(set, sig, &len);
if( !buf )
return NULL;
/* Note that this may alter the contents of buf */
packet = (char *)ringSigFindSubpacket(buf, SIGSUB_REGEXP, 0, &len,
NULL, NULL, NULL, NULL);
pgpAssert( packet );
if (IsPGPError( pgpRegComp( set->pool->context, packet, &rexp ) ) )
return NULL;
sig->s.regexp = (void *) rexp;
}
return sig->s.regexp;
}
/*
* Return true if sig is a valid revocation signature. It must either be
* a self sig, or it must be by a revocation key. May be on either a subkey
* or main key. This does not check for expirations.
*/
PGPBoolean
sigRevokesKey (RingSet const *set, RingObject *sig)
{
RingObject *parent;
RingObject *top;
pgpAssert (OBJISSIG (sig));
pgpAssert (pgpIsRingSetMember(set, sig));
parent = sig->g.up;
if (!OBJISKEY(parent))
return FALSE;
top = parent;
while (!OBJISTOPKEY(top))
top = top->g.up;
if (sig->s.type != ( (top==parent) ? PGP_SIGTYPE_KEY_REVOKE
: PGP_SIGTYPE_KEY_SUBKEY_REVOKE ))
return FALSE;
if ((sig->s.trust & PGP_SIGTRUSTF_TRIED) &&
!(sig->s.trust & PGP_SIGTRUSTF_CHECKED))
return FALSE;
/*
* If untried, don't accept on a subkey. Accept on a top-level key
* if already shown as revoked because we don't store trust packets
* on such keys, so as not to break PGP 2.X.
*/
if (!(sig->s.trust & PGP_SIGTRUSTF_TRIED) &&
((top != parent) ||
!(parent->k.trust & PGP_KEYTRUSTF_REVOKED)))
return FALSE;
if (sig->s.by == top)
return TRUE;
/*
* Here we have a revocation signature which is valid but is by some
* other key. We will accept it only if that is a key which is marked
* as a revocation authorization key by this one.
*/
return ringKeyIsRevocationKey (top, set, sig->s.by);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -