pgprngread.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 2,259 行 · 第 1/5 页
C
2,259 行
/*
* pgpRngRead.c - Read in various parts of a keyring.
*
* Copyright (C) 1994-1997 Pretty Good Privacy, Inc. All rights reserved.
*
* 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.24.2.12 1997/06/11 22:29:47 mhw Exp $
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#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 "pgpCipher.h"
#include "pgpEnv.h"
#include "pgpErr.h"
#include "pgpPubKey.h"
#include "pgpFile.h"
#include "pgpRngRead.h"
#include "pgpSigSpec.h"
#ifndef NULL
#define NULL 0
#endif
/* We have optional code to wrap newer packets in comments */
#define WRAP_NONE 1
/*
* 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 1024u /* Name maximum size */
#define RINGSIG_MAXLEN (2*RINGMPI_MAX) /* Signature maximum size */
#define RINGUNK_MAXLEN RINGSEC_MAXLEN
/* RINGTRUST_MAXLEN is implicit */
/*** 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 piece of magic: because there is no need for the FilePos chain
* to be null-terminated (the number of entries in it is given by the
* mask), physical key ring MEMRINGBIT (which is the last FilePos in the
* chain, so its next pointer is unused) is reserved for memory objects.
* the next pointer and fpos record the location in memory and size of
* the memory buffer holding the object, respectively.
*/
/* Find the position of an object in the given file */
static struct FilePos *
ringFilePos(union RingObject const *obj, struct RingFile const *file)
{
struct FilePos const *pos = &obj->g.pos;
ringmask mask;
pgpAssert(obj->g.mask & file->set.mask);
mask = obj->g.mask & file->set.pool->filemask & (file->set.mask-1);
while (mask) {
pos = pos->ptr.next;
mask &= mask-1;
}
return (struct FilePos *)pos;
}
/* Allocate a FilePos from a RingFile. */
static struct FilePos *
ringFileNewFilePos(struct RingFile *file)
{
struct FilePos *pos = file->freepos;
if (pos) {
file->freepos = pos->ptr.next;
} else {
pos = (struct FilePos *)memPoolNew(&file->fpos,struct FilePos);
if (!pos)
ringAllocErr(file->set.pool);
}
return pos;
}
static void
ringFileFreeFilePos(struct RingFile *file, struct 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 struct FilePos *
ringAddFilePos(union RingObject *obj, struct RingFile *file)
{
ringmask mask = obj->g.mask & file->set.pool->filemask;
ringmask mask2 = file->set.mask;
struct FilePos *pos, *pos2;
int bit;
pgpAssert(!(mask & mask2));
if (mask & (mask2-1)) {
/* FilePos to add is not the first in the chain */
mask &= (mask2-1);
pos2 = ringFileNewFilePos(file);
if (!pos2)
return NULL;
/* Find the predecessor of the one to be added */
pos = &obj->g.pos;
while ((mask &= mask-1) != 0) {
pos = pos->ptr.next;
pgpAssert(pos);
}
/* 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 (!mask) {
/* First and only FilePos on chain */
pos = NULL;
} else {
/* First FilePos; bump down the old first */
bit = ringLsBitFind(mask);
pgpAssert(bit >= 0);
file = &file->set.pool->files[bit];
pos = ringFileNewFilePos(file);
if (!pos)
return NULL;
*pos = *pos2;
}
pos2->ptr.next = pos;
}
obj->g.mask |= mask2;
return pos2;
}
static int
ringAddPos(union RingObject *obj, struct RingFile *file, word32 fpos)
{
struct FilePos *pos;
pos = ringAddFilePos(obj, file);
if (!pos)
return PGPERR_NOMEM;
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, struct RingFile const *file,
word32 fpos)
{
ringmask mask = obj->g.mask & file->set.pool->filemask;
struct FilePos *pos;
pgpAssert(mask & file->set.mask);
mask &= file->set.mask - 1;
for (pos = &obj->g.pos; mask; mask &= mask-1)
pos = pos->ptr.next;
pos->fpos = fpos;
}
/*
* 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, struct RingFile *file)
{
ringmask mask = obj->g.mask & file->set.pool->filemask;
ringmask mask2 = file->set.mask;
struct FilePos *pos, *pos2;
int bit;
/* Is the bit to remove *not* the least significant bit? */
if (mask & (mask2-1)) {
/* FilePos to remove is not the first in the chain */
/* Find the predecessor of the one to be removed */
mask &= (mask2-1);
pos = &obj->g.pos;
while ((mask &= mask-1) != 0) {
pos = pos->ptr.next;
pgpAssert(pos);
}
/* pos->next is the one to be removed */
pos2 = pos->ptr.next;
pgpAssert(pos2);
pos->ptr = pos2->ptr;
if (mask2 == MEMRINGMASK) /* Debugging aid */
pos->ptr.next = NULL;
} else {
/* First FilePos - copy second to first, remove second */
/* Clear this bit from the mask (in case we need to) */
mask &= ~mask2;
/*
* 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 (!mask) {
obj->g.mask &= ~mask2;
if (mask2 == MEMRINGMASK) /* Debugging aid */
obj->g.pos.ptr.next = NULL;
obj->g.pos.fpos = (word32)-1; /* Debugging aid */
return;
}
/* Find the bit of the object we are removing */
bit = ringLsBitFind(mask);
pgpAssert(bit >= 0);
file = &file->set.pool->files[bit];
/* Copy the next pos to the current one */
pos2 = obj->g.pos.ptr.next;
pgpAssert(pos2);
obj->g.pos = *pos2;
}
/* Free the FilePos */
ringFileFreeFilePos(file, pos2);
obj->g.mask &= ~mask2;
}
/*** Closing a Ringfile ***/
/*
* Set the destruction function for a RingFile.
*/
void
ringFileSetDestructor(struct RingFile *file,
void (*destructor)(struct RingFile *, struct PgpFile *, void *),
void *arg)
{
file->destructor = destructor;
file->arg = arg;
}
/*
* Helper function for ringFileDoClose.
*
* Delete the given file's FilePos entries from the objects in
* the given list, and delete the objects if they are no longer
* needed (mask has gone to 0). Recurse as necessary.
*
* Note that this is not used on the main keys list, because
* there we need to preserve dummy keys which this does not
* understand.
*
* This also removes any cached names from objects.
*/
static void
ringFileCloseList(union RingObject **objp, struct RingFile *file)
{
union RingObject *obj;
ringmask const mask = file->set.mask;
ringmask const filemask = file->set.pool->filemask;
while ((obj = *objp) != NULL) {
if (mask & obj->g.mask) {
if (!OBJISBOT(obj))
ringFileCloseList(&obj->g.down, file);
ringRemFilePos(obj, file);
/*
* May have a child obj in the MEMRING which didn't
* get deleted because it was not in this RingFile.
*/
if (!(obj->g.mask & filemask & ~MEMRINGMASK) &&
(OBJISBOT(obj) || !obj->g.down)) {
*objp = obj->g.next;
ringFreeObject(file->set.pool, obj);
} else {
if (OBJISNAME(obj))
ringPurgeCachedName(&obj->n, mask);
objp = &obj->g.next;
}
} else
objp = &obj->g.next;
}
}
/*
* Close the given Ringfile. Returns an error if it can't due to
* conflicts, in which case the file is NOT closed.
*
* This performs four passes over the pool.
* 1. The first does the bulk of the deletion, removing the
* FilePos from the objects and deleting all things
* at levels greater than 1.
* 2. The second rebuilds the sigs-by lists which were broken by
* deleting objects in the middle of them.
* 3. The third finds all keys that are not referenced and do not
* make any signatures, and deletes those keys.
* 4. The fourth rebuilds the hash index of the remaining keys.
*
* Note that the second and third passes delete any allocated-but-not
* linked keys, which are left by ringFileOpen if it runs out of memory
* in mid-operation.
*/
static void
ringFileDoClose(struct RingFile *file)
{
union RingObject *obj, **objp;
struct RingPool *pool = file->set.pool;
ringmask mask = file->set.mask;
ringmask filemask = pool->filemask;
ringmask allocmask = ringAllocMask(pool, &file->set);
int i;
/* Free some memory right away */
ringFilePurgeTrouble(file);
/* 1: Remove everything in the keyring, but don't delete the keys */
for (obj = pool->keys; obj; obj = obj->g.next) {
if (mask & obj->g.mask) {
if (!OBJISBOT(obj))
ringFileCloseList(&obj->g.down, file);
ringRemFilePos(obj, file);
}
}
/* 2: Recreate the shattered sigs-by lists */
ringPoolListSigsBy(pool);
/* 3: Now purge the unneeded keys */
objp = &pool->keys;
while ((obj = *objp) != NULL) {
pgpAssert(OBJISKEY(obj));
if ((obj->g.mask & filemask & ~MEMRINGMASK) || obj->g.down) {
objp = &obj->g.next;
} else if (obj->k.sigsby) {
/* Retain key as a dummy key */
pgpAssert(!(obj->g.mask & allocmask & ~MEMRINGMASK));
pgpAssert(!obj->g.down);
obj->g.mask = 0;
objp = &obj->g.next;
} else {
/* Delete the key */
pgpAssert(!(obj->g.mask & allocmask & ~MEMRINGMASK));
pgpAssert(!obj->g.down);
*objp = obj->g.next;
ringFreeObject(pool, obj);
}
}
/* 4: Re-initialize the hash chains */
ringPoolHash(pool);
/* Clean up the file's memory pools */
memPoolEmpty(&file->strings);
file->freepos = NULL;
memPoolEmpty(&file->fpos);
pgpAssert(!file->set.next);
/*
* If there's nothing in the structs MemPool that's
* allocated, purge all the memory.
*/
if (!pool->keys && !pool->sets) {
for (i = 0; i < RINGTYPE_MAX; i++)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?