pgprngread.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 2,259 行 · 第 1/5 页
C
2,259 行
size_t extralen;
pkalg = 0;
err = ringSigParse((byte const *)pool->pktbuf, pool->pktbuflen,
&pkalg, keyID, &tstamp, &validity, &type,
&hashalg, &extralen, &version);
/* Get key this signature is by */
key = ringPoolFindDummyKey(pool, NULL, pkalg, keyID);
if (!key)
return NULL;
/* Search for matching sigs */
fsigp = &parent->g.down;
for (sigp = fsigp; (sig=*sigp) != NULL; sigp = &sig->g.next) {
if (OBJISSEC(sig) || OBJISSIG(sig))
fsigp = &sig->g.next; /* predecessor to new sig */
if (OBJISSIG(sig)
&& sig->s.by == key
&& (sig->s.by->k.pkalg == pkalg || pkalg==1) /* ViaCrypt */
&& sig->s.tstamp == tstamp
&& sig->s.type == type
&& sig->s.version == version
&& sig->s.validity == validity
&& sig->s.hashalg == hashalg
&& !(sig->g.flags & SIGF_ERROR) == !err
&& !(sig->g.flags & SIGF_NONFIVE) == (extralen == 5)
&& (i = sigsdiffer(file, sig)) <= 0)
{
return i<0 ? NULL : sig;
}
}
/* Not found - allocate a new sig */
sig = ringNewSig(pool);
if (sig) {
/* Add new sig before any user ID's */
sig->g.next = *fsigp;
*fsigp = sig;
sig->s.by = (union RingObject *)key;
sig->g.up = parent;
if (err)
sig->g.flags |= SIGF_ERROR;
if (extralen != 5)
sig->g.flags |= SIGF_NONFIVE;
if (OBJISKEY(parent))
sig->g.flags |= SIGF_KEY;
sig->s.tstamp = tstamp;
sig->s.validity = validity;
sig->s.type = type;
sig->s.version = version;
sig->s.hashalg = hashalg;
sig->s.trust = 0;
}
return sig;
}
/*
* Return 1 if the blob in the ring's pktbuf differs from the
* blob in its various homes, 0 if it is the same, and <0 if there
* is some sort of error.
* Does *not* alter file1's read position unless there is an error.
*/
static int
unkdiffer(struct RingFile *file1, union RingObject const *unk)
{
struct RingPool *pool = file1->set.pool;
struct RingFile *file2;
long retpos=0;
int i;
int bit;
/* Find a matching unk */
file2 = ringBestFile(pool, unk, 0);
bit = ringLsBitFind(unk->g.mask & pool->filemask);
pgpAssert(bit >= 0);
file2 = &pool->files[bit];
pgpAssert (file2->f || file2->set.mask == MEMRINGMASK);
if (file2 == file1 && file1->f && (retpos=pgpFileTell(file1->f)) < 0) {
ringErr(file1, pgpFileTell(file1->f), PGPERR_KEYIO_FTELL);
return PGPERR_KEYIO_FTELL;
}
if (file2->f &&
pgpFileSeek(file2->f, unk->g.pos.fpos, SEEK_SET) != 0) {
ringErr(file2, unk->g.pos.fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
i = ringPacketDiffers(file2, unk, PKTBYTE_TYPE(unk->u.pktbyte),
pool->pktbuflen+1);
if (file2 == file1 && file1->f &&
pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
ringErr(file1, unk->g.pos.fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
return i;
}
/*
* Get a struct RingUnk on the given chain matching the one in the ring's
* pktbuf with the given pktbyte. Returns 0 if it runs out of memory
* or can't read the file. (The ring's error is set to reflect this.)
* It does *not* add the FilePos or set the mask bit.
* Does *not* alter the given file's read position unless there is an error.
*/
static union RingObject *
ringFindUnk(struct RingFile *file, union RingObject *parent, byte pktbyte)
{
struct RingPool *pool = file->set.pool;
union RingObject *unk, **unkp;
word32 hash;
int i;
hash = ringHashBuf((byte const *)pool->pktbuf, pool->pktbuflen);
for (unkp = &parent->g.down; (unk=*unkp) != NULL;
unkp = &unk->g.next) {
/*
* If the type, hash and pktbyte match, try to compare...
* Note that the pktbyte *must* match or namesdiffer()
* will complain loudly.
*/
if (OBJISUNK(unk)
&& unk->u.hash == hash
&& unk->u.pktbyte == pktbyte
&& (i = unkdiffer(file, unk)) <= 0)
{
return i<0 ? NULL : unk;
}
}
/* Failed to find a name - create one */
unk = ringNewUnk(pool);
if (unk) {
*unkp = unk;
unk->g.up = parent;
unk->u.pktbyte = pktbyte;
unk->u.hash = hash;
/* Default new names to unknown trust */
}
return unk;
}
/* Return the list of trpuble associated with a RingFile. */
struct RingTrouble const *
ringFileTrouble(struct RingFile const *file)
{
return file->trouble;
}
/*
* Functions for manipulating the Trouble list.
*/
/* Zero out a RingFile's Trouble list; it has been dealt with. */
void
ringFilePurgeTrouble(struct RingFile *file)
{
memPoolEmpty(&file->troublepool);
file->trouble = NULL;
file->troubletail = &file->trouble;
}
/*
* Log some trouble with a RingFile.
*/
static int
ringFileLog(struct RingFile *file, union RingObject *obj, word32 num,
word32 fpos, int type)
{
struct RingTrouble *t;
t = (struct RingTrouble *)memPoolNew(&file->troublepool,
struct RingTrouble);
if (!t)
return PGPERR_NOMEM;
t->next = NULL;
t->obj = obj;
t->num = num;
t->fpos = fpos;
t->type = type;
*file->troubletail = t;
file->troubletail = &t->next;
return 0;
}
/*
* @@@ This needs fixing - we should complain about a key without
* names in *this* file, even if it has names in others.
*/
static union RingObject const *
ringKeyHasName(union RingObject const *obj)
{
for (obj = obj->g.down; obj; obj = obj->g.next)
if (OBJISNAME(obj))
break;
return obj;
}
/*
* How to skip things. Various helper functions return either
* negative fatal error codes or these codes indicating what to
* do to recover from any warnings. These never exceed 15 bits,
* so "int" is the right type.
*/
typedef int skip_t;
#define SKIP_TRUST 1
#define SKIP_SIG 2
#define SKIP_NAME 4
#define SKIP_SUBKEY 8
#define SKIP_KEY 16
#define SKIP_SIGS (SKIP_TRUST | SKIP_SIG)
#define SKIP_TO_KEY (SKIP_SIGS | SKIP_NAME | SKIP_SUBKEY)
#define PB_PUBKEY(key) (OBJISTOPKEY(key) ? \
PKTBYTE_BUILD(PKTBYTE_PUBKEY, 0) : \
PKTBYTE_BUILD(PKTBYTE_PUBSUBKEY, 0))
#define PB_SECKEY(key) (OBJISTOPKEY(key) ? \
PKTBYTE_BUILD(PKTBYTE_SECKEY, 0) : \
PKTBYTE_BUILD(PKTBYTE_SECSUBKEY, 0))
#define PB_SIG PKTBYTE_BUILD(PKTBYTE_SIG, 0)
/*
* Add a new key to the Pool, with its *parent* at the given level
* (0 means adding top-level key) in the RingIterator. Leave the
* RingIterator pointing to the newly created key. Return <0 on error,
* 0 if the key was created, and a skip code > 0 if it was created with
* a warning of some sort.
*/
static int
ringAddKey(struct RingFile *file, struct RingIterator *iter, word32 fpos,
int trusted, byte pkttype)
{
union RingObject *key, *sec, *parent;
byte pkalg, keyID[8];
word16 keybits;
word32 tstamp;
word16 validity;
int i, err, level;
pkalg = 0;
err = ringKeyParse((byte const *)file->set.pool->pktbuf,
file->set.pool->pktbuflen, &pkalg,
keyID, &keybits, &tstamp, &validity, 0);
if (pkttype == PKTBYTE_PUBSUBKEY) {
/* Subkey */
if (!iter->level) {
i = ringFileLog(file, NULL, 0, fpos,
PGPERR_TROUBLE_UNXSUBKEY);
return i < 0 ? i : SKIP_SIGS;
}
parent = iter->stack[0];
level = 1;
} else {
parent = NULL;
level = 0;
if (iter->level) {
key = iter->stack[0];
pgpAssert(OBJISKEY(key));
/* Complain about a key with no Names */
if (!ringKeyHasName(key)) {
i = ringFileLog(file, key, 0,
ringFilePos(key, file)->fpos,
PGPERR_TROUBLE_BAREKEY);
if (i < 0)
return i;
}
/* @@@ Should we not care about this? */
/* If keys not in sorted order, dirty */
#if 0
/* @@@ ringSortKeys orders keys by algorithm
so this test no longer works. */
if (ringKeyIDcmp(key->k.keyID, keyID) > 0)
ringFileMarkDirty(file);
#endif
}
}
/* Find the matching key structure */
key = ringPoolFindDummyKey(file->set.pool, parent, pkalg, keyID);
if (!key)
return ringFileError(file)->error;
/* See if it's a new key or the same key */
if (key->g.mask == 0) {
/* Newly created dummy key; fill in info */
if (pkttype == PKTBYTE_PUBSUBKEY && OBJISTOPKEY(key)) {
/*
* Here on a former dummy top-level key which
* has turned out to be a subkey. Dummy key
* would have been created if we saw a sig by
* it. Change key to a subkey.
*/
i = ringFileLog(file, NULL, 0, fpos,
PGPERR_TROUBLE_SIGSUBKEY);
if (i < 0)
return i;
ringPoolUnlinkKey(file->set.pool, key);
key->k.flags |= RINGOBJF_SUBKEY;
ringPoolLinkKey(file->set.pool, parent, key,
pkalg, keyID);
}
key->k.pkalg = pkalg; /* ViaCrypt */
key->k.tstamp = tstamp;
key->k.validity = validity;
key->k.keybits = keybits;
key->k.trust = 0;
if (err)
key->g.flags |= KEYF_ERROR;
} else if (keybits != key->k.keybits
|| pkalg != key->k.pkalg /* ViaCrypt */
|| tstamp != key->k.tstamp
/* || validity != key->k.validity Validity may be in sig */
|| parent != (OBJISTOP(key) ? NULL : key->g.up)
|| !(key->g.flags & KEYF_ERROR) != !err)
{
i = ringFileLog(file, key, 0, fpos,
PGPERR_TROUBLE_DUPKEYID);
return i < 0 ? i : SKIP_TO_KEY;
} else if ((i=keysdiffer(file,key,PB_PUBKEY(key))) != 0) {
if (i < 0)
return i;
if ((OBJISTOPKEY(key) && pkttype==PKTBYTE_PUBSUBKEY) ||
(OBJISSUBKEY(key) && pkttype==PKTBYTE_PUBKEY)) {
i = ringFileLog(file, key, 0, fpos,
PGPERR_TROUBLE_KEYSUBKEY);
return (i < 0) ? i : SKIP_TO_KEY;
}
/* KLUDGE: version byte bug */
/*
* A key with a version byte of 2 only overrides previous
* keys with a byte of 3 if they are all untrusted
* secret keys and this is either a secret key or from
* a trusted public keyring. A key with a version byte
* of 3 is only overridden if it's secret and previous
* keys include a secret key or a trusted public key.
*/
if (i == PGPVERSION_2
&& trusted
&& !(key->g.flags & RINGOBJF_TRUST)
&& !((ringKeySecMask(key) ^ key->g.mask)
& file->set.pool->filemask))
{
i = ringFileLog(file, key, 0, fpos,
PGPERR_TROUBLE_VERSION_BUG_PREV);
if (i < 0)
return i;
/* Set all those secret version bug flags */
for (sec = key->g.down; sec; sec = sec->g.next)
if (OBJISSEC(sec))
sec->g.flags |= SECF_VERSION_BUG;
} else {
/* End of KLUDGE */
i = ringFileLog(file, key, 0, fpos,
PGPERR_TROUBLE_DUPKEYID);
if (i < 0)
return i;
return i < 0 ? i : SKIP_TO_KEY;
}
}
/*
* Already present in this keyring?
* If so, accept following sigs & userids (they may
* not be duplicates), but flag a warning.
*/
if (key->g.mask & file->set.mask) {
i = ringFileLog(file, key, 0, fpos, PGPERR_TROUBLE_DUPKEY);
if (i < 0)
goto failed;
i = SKIP_TRUST;
} else {
/* Add the FilePos */
i = ringAddPos(key, file, fpos);
if (i < 0)
goto failed;
}
/* Add successful; indicate it in the mask */
key->g.mask |= iter->set.mask;
iter->stack[level] = key;
iter->level = level+1;
return i;
failed:
if (!key->g.mask)
ringFreeDummyKey(file->set.pool, key);
return i;
}
/*
* Add a new secret to the Pool, as two objects: a key (with its *parent*
* at the given level in the RingIterator; 0 means add a top-level key)
* and a signature as its child. Leave the RingIterator pointing to the
* newly created secret. Return <0 on error, 0 if the key was created,
* and a skip code >0 if they key was created with a warning of some sort.
*
* This is *ridiculously* hairy. Is there a way to clean it up?
* @@@ TODO: Add PGPERR_TROUBLE_OLDSEC and _NEWSEC handling.
*/
static int
ringAddSec(struct RingFile *file, struct RingIterator *iter, word32 fpos,
byte pkttype)
{
union RingObject *key, *sec, *parent;
byte pkalg, keyID[8];
word16 keybits;
word32 tstamp;
word16 validity;
int i, err;
int level;
int flags = 0;
pkalg = 0;
err = ringKeyParse((byte const *)file->set.pool->pktbuf,
file->set.pool->pktbuflen, &pkalg,
keyID, &keybits, &tstamp, &validity, 1);
if (pkttype == PKTBYTE_SECSUBKEY) {
/* Subkey */
if (!iter->level) {
i = ringFileLog(file, NULL, 0, fpos,
PGPERR_TROUBLE_UNXSUBKEY);
return i < 0 ? i : SKIP_SIGS;
}
parent = iter->stack[0];
level = 1;
} else {
parent = NULL;
level = 0;
if (iter->level) {
key = iter->stack[0];
pgpAssert(OBJISKEY(key));
/* Complain about a key with no Names */
if (!ringKeyHasName(key)) {
i = ringFileLog(file, key, 0,
ringFilePos(key, file)->fpos,
PGPERR_TROUBLE_BAREKEY)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?