📄 pgprngread.c
字号:
/*
* pgpRngRead.c - Read in various parts of a keyring.
*
* The big function (>500 lines, yeep!) is ringFileOpen(); it opens another
* keyring and merges it with the collection in memory. Most of the others
* are its helpers. This is where PGPlib's great robustness in the face of
* badly mangled keyrings is achieved. *Every* keyring comes through here,
* and it validates its inputs to the point of paranoia.
*
* This file is too big - what should be split out?
* There are a lot of similar-but-not-quite functions. Perhaps some
* rethinking will allow parts of them to be merged?
*
* Written by Colin Plumb.
*
* $Id: pgpRngRead.c,v 1.96 1999/04/14 05:45:21 hal Exp $
*/
#include "pgpConfig.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "pgpDebug.h"
#include "pgpMakeSig.h"
#include "pgpMemPool.h"
#include "pgpPktByte.h"
#include "pgpRngMnt.h"
#include "pgpRngPars.h"
#include "pgpRngPkt.h"
#include "pgpRngPriv.h"
#include "pgpTrust.h"
#include "pgpTrstPkt.h" /* for PGP_SIGTRUSTF_CHECKED_TRIED */
#include "pgpHash.h"
#include "pgpKeySpec.h"
#include "pgpMem.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpEnv.h"
#include "pgpErrors.h"
#include "pgpPubKey.h"
#include "pgpFile.h"
#include "pgpRngRead.h"
#include "pgpSigSpec.h"
#include "pgpContext.h"
#include "pgpX509Priv.h"
#ifndef NULL
#define NULL 0
#endif
static PGPContextRef
RingSetGetContext( const RingSet *set )
{
pgpAssert( pgpContextIsValid( set->pool->context ) );
return( set->pool->context );
}
/*
* The largest legal PGP key uses a 64Kbit key, which is 8Kbytes.
* As a public key, there's also 12 bytes of overhead, plus a
* public exponent (usually 1 byte, sometimes 3, it's just stupid
* to make it any larger).
* Stored in a secret key an extra 11+IV bytes of overhead and
* the secret exponent (8K), factors p and q (4+4=8K), and multiplicative
* inverse u (4K). A total of 28K of data, plus 23+IV+e extra bytes.
* With an 8-byte IV, that's 31+e bytes. Add an extra byte to allow
* for p and q of differing lengths.
* But for now, reduce this by a factor of 8, to 8Kbits, which changes
* the maximum sizes to 1K+overhead and 3.5K + overhead.
*
* Without these limits, a non-fatal error (object too big) becomes
* a fatal error (out of memory) and the implementation becomes
* less robust. However, the limits can be set quite high without
* harm. (Keep the maximum key size to 64K, though.)
*
* The limits above were derived for RSA keys. DSA/ElG keys have a prime
* p, a small (~160 bit) prime q, a generator g, and a public exponent y.
* That's four numbers, one of them small. If we allow enough space for four
* full-sized numbers that should be safe. Secrets have in addition a
* secret exponent x, generally small, so allow an additional number.
* Signatures are small with DSA, two 160 bit numbers. However the new
* signature packets can in principle have a lot of data. Allow two full
* sized numbers to give us plenty of room; we may have to increase the value
* in the future.
*/
#define RINGMPI_MAX 1024 /* Maximum 8Kbits */
#define RINGKEY_MAXLEN (4*RINGMPI_MAX) /* Public key maximum size */
#define RINGSEC_MAXLEN (5*RINGMPI_MAX) /* Secret key maximum size */
#define RINGNAME_MAXLEN 150000 /* Name/attribute maximum size */
#define RINGSIG_MAXLEN 150000 /* Signature maximum size */
#define RINGCRL_MAXLEN MAX_PGPSize /* CRL maximum size */
#define RINGUNK_MAXLEN RINGSEC_MAXLEN
/* RINGTRUST_MAXLEN is implicit */
/* Threshold for caching name/attribute objects in memory */
#define NAMECACHETHRESHOLD 1024
/*** Working with the FilePos chain ***/
/*
* A note about the FilePos chain. Each object has one FilePos right
* inside itself, which is the head of a list of external (allocated)
* ones. There is one FilePos for each key file an object exists in,
* and they are kept in increasing order by bit number.
* Every object (except dummy keys, which aren't excessively numerous,
* especially in large keyrings) is present in at least one physical
* keyring, so this saves one next pointer when we're trying to conserve
* memory for MS-DOS, at the expense of complicating the task of
* adding to and removing from the list.
*
* This is because the first entry in the chain is statically allocated.
* An actual allocation is performed when an entry is added to the
* chain in a location other than the first, or is bumped from first
* place by something else. A FilePos is freed when an entry is deleted
* from the chain, or the first one is deleted and the second moves into
* its place.
*
* One more special feature: the MEMRING filepos is put as the last entry
* in the chain. In that filepos, the "next" pointer actually points at
* the memory data, and the fpos field holds the size of the memory block.
*/
/* Find the position of an object in the given file */
static FilePos *
ringFilePos(union RingObject const *obj, RingFile const *file)
{
FilePos const *pos = &obj->g.pos;
PGPVirtMask mask;
RingPool *pool = file->set.pool;
pgpVirtMaskInit (pool, &mask);
pgpVirtMaskCopy (pool, &obj->g.mask, &mask);
pgpVirtMaskAND (pool, &pool->filemask, &mask);
/* Keep only bits before the one we are interested in */
/* But for MEMRING go to the last in the chain */
pgpVirtMaskANDNOT(pool, &pool->memringmask, &mask);
if (!pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask)) {
PGPInt32 filebit = pgpVirtMaskLSBit (&file->set.mask);
pgpVirtMaskClearGreaterBits (pool, &mask, filebit);
}
while (!pgpVirtMaskIsEmpty(&mask)) {
PGPInt32 bit = pgpVirtMaskLSBit (&mask);
pgpAssert (bit >= 0);
pgpVirtMaskClearBit (pool, &mask, bit);
pos = pos->ptr.next;
}
pgpVirtMaskCleanup (pool, &mask);
return (FilePos *)pos;
}
/* Allocate a FilePos from a RingFile. */
static FilePos *
ringFileNewFilePos(RingFile *file)
{
FilePos *pos = file->freepos;
if (pos) {
file->freepos = pos->ptr.next;
} else {
pos = (FilePos *)memPoolNew(&file->fpos,FilePos);
if (!pos)
ringAllocErr(file->set.pool);
}
return pos;
}
static void
ringFileFreeFilePos(RingFile *file, FilePos *pos)
{
pos->ptr.next = file->freepos;
file->freepos = pos;
}
/*
* Allocate and add a FilePos to the object's chain in the right place.
* This function makes no attempt to initialize the resultant FilePos.
*
* NOTE that the bit specified to add may or may not be present in
* the ring's filemask. This function must not care.
*/
static FilePos *
ringAddFilePos(union RingObject *obj, RingFile *file)
{
RingPool *pool = file->set.pool;
PGPVirtMask mask, tmpmask;
FilePos *pos, *pos2;
PGPInt32 bit;
RingFile *file2;
pgpVirtMaskInit (pool, &mask);
pgpVirtMaskInit (pool, &tmpmask);
pgpVirtMaskCopy (pool, &obj->g.mask, &mask);
pgpVirtMaskAND (pool, &pool->filemask, &mask);
pgpAssert (!pgpVirtMaskIsOverlapping (&mask, &file->set.mask));
pgpVirtMaskCopy (pool, &mask, &tmpmask);
pgpVirtMaskANDNOT (pool, &pool->memringmask, &tmpmask);
if (!pgpVirtMaskIsEqual(&pool->memringmask, &file->set.mask)) {
PGPInt32 filebit = pgpVirtMaskLSBit (&file->set.mask);
pgpVirtMaskClearGreaterBits (pool, &tmpmask, filebit);
}
if (!pgpVirtMaskIsEmpty (&tmpmask)) {
/* FilePos to add is not the first in the chain */
pgpVirtMaskCopy (pool, &tmpmask, &mask);
pos2 = ringFileNewFilePos(file);
if (!pos2)
return NULL;
/* Find the predecessor of the one to be added */
pos = &obj->g.pos;
bit = pgpVirtMaskLSBit (&mask);
pgpAssert (bit >= 0);
pgpVirtMaskClearBit (pool, &mask, bit);
while ((bit = pgpVirtMaskLSBit (&mask)) >= 0) {
pos = pos->ptr.next;
pgpAssert(IsntNull(pos));
pgpVirtMaskClearBit (pool, &mask, bit);
}
/* Insert pos2 into the chain after pos */
pos2->ptr.next = pos->ptr.next;
pos->ptr.next = pos2;
} else {
/* First FilePos in the chain */
pos2 = &obj->g.pos;
if (pgpVirtMaskIsEmpty(&mask)) {
/* First and only FilePos on chain */
pos = NULL;
} else {
/* First FilePos; bump down the old first */
bit = pgpVirtMaskLSBit(&mask);
pgpAssert(bit >= 0);
/* Allocate pos from pool for existing bit */
file2 = file->set.pool->files[bit];
pos = ringFileNewFilePos(file2);
if (!pos)
return NULL;
*pos = *pos2;
}
pos2->ptr.next = pos;
}
pgpVirtMaskOR (pool, &file->set.mask, &obj->g.mask);
pgpVirtMaskCleanup (pool, &mask);
pgpVirtMaskCleanup (pool, &tmpmask);
return pos2;
}
static int
ringAddPos(union RingObject *obj, RingFile *file, PGPUInt32 fpos)
{
FilePos *pos;
pos = ringAddFilePos(obj, file);
if (!pos)
return kPGPError_OutOfMemory;
pos->fpos = fpos;
return 0;
}
/*
* This is needed in one obscure error case to keep things
* consistent. The case is when a secret key appears in the same
* file as the corresponding public key, only later.
*/
static void
ringAlterFilePos(union RingObject *obj, RingFile const *file,
PGPUInt32 fpos)
{
PGPVirtMask mask;
RingPool *pool = file->set.pool;
FilePos *pos;
pgpVirtMaskInit (pool, &mask);
pgpVirtMaskCopy (pool, &obj->g.mask, &mask);
pgpVirtMaskAND (pool, &pool->filemask, &mask);
pgpAssert (pgpVirtMaskIsOverlapping(&mask, &file->set.mask));
pgpVirtMaskANDNOT (pool, &pool->memringmask, &mask);
if (!pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask)) {
PGPInt32 filebit = pgpVirtMaskLSBit (&file->set.mask);
pgpVirtMaskClearGreaterBits (pool, &mask, filebit);
}
pos = &obj->g.pos;
while (!pgpVirtMaskIsEmpty (&mask)) {
PGPInt32 bit = pgpVirtMaskLSBit (&mask);
pgpVirtMaskClearBit (pool, &mask, bit);
pos = pos->ptr.next;
}
pos->fpos = fpos;
pgpVirtMaskCleanup (pool, &mask);
}
/*
* Remove a FilePos from an object's list.
*
* file is the filepos corresponding to "bit", pos is the head of a
* FilePos chain, mask is the bitmask of physical key rings, and
* bit is the number of the ring to have its position removed.
*
* NOTE that the bit specified to remove may or may not be present in
* the ring->filemask. This function must not care.
*/
static void
ringRemFilePos(union RingObject *obj, RingFile *file)
{
PGPVirtMask mask, tmpmask;
RingPool *pool = file->set.pool;
FilePos *pos, *pos2;
PGPInt32 bit;
RingFile *file2;
pgpVirtMaskInit (pool, &mask);
pgpVirtMaskInit (pool, &tmpmask);
pgpVirtMaskCopy (pool, &obj->g.mask, &mask);
pgpVirtMaskAND (pool, &pool->filemask, &mask);
/* Is the bit to remove *not* the least significant bit? */
pgpVirtMaskCopy (pool, &mask, &tmpmask);
pgpVirtMaskANDNOT (pool, &pool->memringmask, &tmpmask);
if (!pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask)) {
bit = pgpVirtMaskLSBit (&file->set.mask);
pgpVirtMaskClearGreaterBits (pool, &tmpmask, bit);
}
if (!pgpVirtMaskIsEmpty (&tmpmask)) {
/* FilePos to remove is not the first in the chain */
/* Find the predecessor of the one to be removed */
pgpVirtMaskCopy (pool, &tmpmask, &mask);
pos = &obj->g.pos;
bit = pgpVirtMaskLSBit (&mask);
pgpAssert (bit >= 0);
pgpVirtMaskClearBit (pool, &mask, bit);
while ((bit = pgpVirtMaskLSBit (&mask)) >= 0) {
pos = pos->ptr.next;
pgpAssert(IsntNull(pos));
pgpVirtMaskClearBit (pool, &mask, bit);
}
/* pos->next is the one to be removed */
pos2 = pos->ptr.next;
pgpAssert(IsntNull(pos2));
pos->ptr = pos2->ptr;
if (pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask))
pos->ptr.next = NULL; /* debugging aid */
file2 = file;
} else {
/* First FilePos - copy second to first, remove second */
/* Clear this bit from the mask (in case we need to) */
pgpVirtMaskANDNOT (pool, &file->set.mask, &mask);
/*
* That's it? Well, return then. The caller better
* deallocate this object, 'cause it no longer exists
* anywhere. Use position -1 to mark an unused slot.
*/
if (pgpVirtMaskIsEmpty(&mask)) {
pgpVirtMaskANDNOT (pool, &file->set.mask, &obj->g.mask);
if (pgpVirtMaskIsEqual (&file->set.mask, &pool->memringmask))
obj->g.pos.ptr.next = NULL; /* Debugging aid */
obj->g.pos.fpos = (PGPUInt32)-1; /* Debugging aid */
pgpVirtMaskCleanup (pool, &mask);
pgpVirtMaskCleanup (pool, &tmpmask);
return;
}
/* Find the bit of the fpos we are removing, the 2nd fpos in list */
/* Note we have already cleared the bit for the 1st fpos */
pgpVirtMaskANDNOT (pool, &pool->memringmask, &mask);
if (pgpVirtMaskIsEmpty(&mask))
bit = 0;
else
bit = pgpVirtMaskLSBit (&mask);
pgpAssert(bit >= 0);
file2 = file->set.pool->files[bit]; /* where to stash reclaimed pos */
/* Copy the next pos to the current one */
pos2 = obj->g.pos.ptr.next;
pgpAssert(IsntNull(pos2));
obj->g.pos = *pos2;
}
/* Free the FilePos */
ringFileFreeFilePos(file2, pos2);
pgpVirtMaskANDNOT (pool, &file->set.mask, &obj->g.mask);
pgpVirtMaskCleanup (pool, &mask);
pgpVirtMaskCleanup (pool, &tmpmask);
}
/* Remove an object and its children from a specific file */
/* If an object is left unhomed, delete it */
static void
ringRemFileObjChildren(union RingObject *obj, RingFile *file)
{
RingPool *pool = file->set.pool;
RingObject *obj1, *nextobj1;
RingObject *obj2, *nextobj2;
if (pgpIsRingSetMember(&file->set, obj)) {
ringRemFilePos(obj, file);
if (!OBJISBOT(obj)) {
for (obj1=obj->g.down; obj1; obj1=nextobj1) {
nextobj1 = obj1->g.next;
if (pgpIsRingSetMember(&file->set, obj1)) {
ringRemFilePos(obj1, file);
if (!OBJISBOT(obj1)) {
for (obj2=obj1->g.down; obj2; obj2=nextobj2) {
nextobj2 = obj2->g.next;
if (pgpIsRingSetMember(&file->set, obj2)) {
ringRemFilePos(obj2, file);
if (!pgpVirtMaskIsOverlapping (&obj2->g.mask,
&pool->filemask))
ringRemObject (pool, obj2);
}
}
}
if (!pgpVirtMaskIsOverlapping (&obj1->g.mask,
&pool->filemask)) {
/* Parents share all homes of children */
pgpAssert (OBJISBOT(obj1) || IsNull(obj1->g.down));
ringRemObject (pool, obj1);
}
}
}
}
if (!pgpVirtMaskIsOverlapping (&obj->g.mask, &pool->filemask)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -