pgprngread.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 2,259 行 · 第 1/5 页
C
2,259 行
if (pgpFileRead(&c, 1, f) != 1) {
i = pgpFileError(f) ? PGPERR_KEYIO_READING : PGPERR_KEYIO_EOF;
ringErr(file, pos->fpos, i);
return i;
}
i = c & 255;
magic = 0; /* First char the same */
if (i != ((byte *)pool->pktbuf)[0]) {
if ((i ^ ((byte *)pool->pktbuf)[0]) != 1
|| (i & ((byte *)pool->pktbuf)[0]) != 2)
return 1;
magic = ((byte *)pool->pktbuf)[0]; /* First char magic */
}
i = fileUnequalBuf(f, pool->pktbuf+1, (size_t)len-1);
if (i < 0)
ringErr(file, pos->fpos, i);
return i ? i : magic;
}
/*
* Return 1 if the key in the ring's pktbuf differs from the
* key in its other 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.
* (I.e. if it needs to seek file1, it saves and restores the file
* position. It doesn't bother for other files. Use the MEMRING file
* if you don't need this feature.)
*
* SPECIAL CASE:
* Returns >1 if the version byte bug was detected. This is the case
* wherein version 2.6 would write out an edited secret key with a
* version byte of 3 even if it was originally 2.
* This function returns the current pktbuf's version byte (2 or 3)
* if the keys are identical except that the version byte differs
* from something read previously.
* The caller must decide what sort of trouble to log.
*/
static int
keysdiffer(struct RingFile *file1, union RingObject const *key, int pktbyte)
{
struct RingPool *pool = file1->set.pool;
struct RingFile *file2;
size_t savelen, publen;
ringmask secmask;
word32 max;
int i, type;
long retpos=0;
pgpAssert(OBJISKEY(key));
pgpAssert(file1->f || file1->set.mask == MEMRINGMASK);
/*
* If this is a secret key, find the prefix which is a public key,
* and limit it to that if reasonable.
*/
savelen = pool->pktbuflen;
if ((PKTBYTE_TYPE(pktbyte) == PKTBYTE_SECKEY ||
PKTBYTE_TYPE(pktbyte) == PKTBYTE_SECSUBKEY)
&& !(key->g.flags & KEYF_ERROR))
{
publen = ringKeyParsePublicPrefix((byte const *)pool->pktbuf,
pool->pktbuflen);
if (publen)
pool->pktbuflen = publen;
}
/* Find a file containing the key - try for public first */
secmask = ringKeySecMask(key);
file2 = ringBestFile(pool, key, secmask);
if (file2) {
max = (word32)-1;
type = OBJISTOPKEY(key) ? PKTBYTE_PUBKEY : PKTBYTE_PUBSUBKEY;
} else {
file2 = ringBestFile(pool, key, 0);
pgpAssert(file2);
max = (word32)pool->pktbuflen;
type = OBJISTOPKEY(key) ? PKTBYTE_SECKEY : PKTBYTE_SECSUBKEY;
}
if (file2 == file1 && file1->f && (retpos=pgpFileTell(file1->f)) < 0) {
ringErr(file1, pgpFileTell(file1->f), PGPERR_KEYIO_FTELL);
return PGPERR_KEYIO_FTELL;
}
i = ringPacketDiffers(file2, key, type, max);
/*
* If we compared against a secret key, and encountered the version
* bug, and the version bug has already been noted, ignore the
* difference.
*/
if (i == PGPVERSION_2
&& type == PKTBYTE_SECKEY
&& key->g.flags & SECF_VERSION_BUG)
i = 0;
if (file2 == file1 && file1->f &&
pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
ringErr(file1, pgpFileTell(file1->f), PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
/* Restore pktbuflen, may have been changed above */
pool->pktbuflen = savelen;
return i;
}
/*
* Return 1 if the secret in the ring's pktbuf differs from the
* key in its other 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.
*
* SPECIAL CASE:
* Returns >1 if the version byte bug was detected. This is the case
* wherein version 2.6 would write out an edited secret key with a
* version byte of 3 even if it was originally 2.
* This function returns the current pktbuf's version byte (2 or 3)
* if the keys are identical except that the version byte differs
* from something read previously.
* The caller must decide what sort of trouble to log.
*/
/*
* Return 1 if the signature in the ring's pktbuf differs from the
* sig 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.
* (I.e. if it needs to seek file1, it saves and restores the file
* position. It doesn't bother for other files. Use the MEMRING file
* if you don't need this feature.)
*/
static int
secsdiffer(struct RingFile *file1, union RingObject const *sec)
{
struct RingPool *pool = file1->set.pool;
struct RingFile *file2;
long retpos=0;
byte pktbyte;
int i;
pgpAssert(OBJISSEC(sec));
/* Find a matching signature */
file2 = ringBestFile(pool, sec, 0);
pgpAssert(file2);
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;
}
pktbyte = OBJISTOPKEY(sec->g.up) ? PKTBYTE_SECKEY :
PKTBYTE_SECSUBKEY;
i = ringPacketDiffers(file2, sec, pktbyte, (word32)-1);
if (i < 0)
return i;
if (file2 == file1 && file1->f &&
pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
ringErr(file1, sec->g.pos.fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
return i;
}
static union RingObject *
ringFindSec(struct RingFile *file, union RingObject *parent)
{
struct RingPool *pool = file->set.pool;
union RingObject *sec, **secp;
int i;
/* Properties of the secret */
word32 hash;
hash = ringHashBuf((byte const *)pool->pktbuf, pool->pktbuflen);
/* Search for matching sigs */
for (secp=&parent->g.down; (sec=*secp) != NULL; secp=&sec->g.next) {
if (OBJISSEC(sec)
&& sec->c.hash == hash
&& (i = secsdiffer(file, sec)) <= 0)
return i<0 ? NULL : sec;
}
/* Not found - allocate a new secret */
sec = ringNewSec(pool);
if (sec) {
/*
* Make secret object the first thing. This is assumed by
* ringFindSig which tries to keep sigs together just past
* the sec obj. Especially important with subkeys where it's
* hard to tell which sigs go with which keys as we read.
*/
sec->g.next = parent->g.down;
parent->g.down = sec;
sec->g.up = parent;
sec->c.hash = hash;
}
return sec;
}
/*
* Return 1 if the name in the ring's pktbuf differs from the
* name 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.
* (I.e. if it needs to seek file1, it saves and restores the file
* position. It doesn't bother for other files. Use the MEMRING file
* if you don't need this feature.)
*/
static int
namesdiffer(struct RingFile *file1, union RingObject const *name)
{
struct RingPool *pool = file1->set.pool;
struct RingFile *file2;
long retpos=0;
int i;
/* Find a matching name */
file2 = ringBestFile(pool, name, 0);
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, name->g.pos.fpos, SEEK_SET) != 0) {
ringErr(file2, name->g.pos.fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
i = ringPacketDiffers(file2, name, PKTBYTE_NAME, (word32)-1);
if (file2 == file1 && file1->f &&
pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
ringErr(file1, name->g.pos.fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
return i;
}
/*
* Exported variant of namesdiffer. This has a similar function, but
* a very different interface - it does not assume that the name has been
* fetched into the pktbuf.
* Returns 1 if the two names differ, 0 if the same, < 0 on error.
*/
int
ringNamesDiffer (struct RingSet const *set, union RingObject *name1,
union RingObject *name2)
{
char const *buf1, *buf2; /* Pointers to the names */
unsigned len, tlen;
word32 hash1, hash2; /* Hashes of the two names */
pgpAssert (OBJISNAME(name1));
pgpAssert (OBJISNAME(name2));
pgpAssert (set->mask & name1->g.mask & name2->g.mask);
/* Quick test of lengths */
len = name1->n.len;
if (len != name2->n.len)
return 1;
/* Trivial case: both names are in memory */
if (NAMEISCACHED(&name1->n) && NAMEISCACHED(&name2->n))
return memcmp(name1->n.name.ptr, name2->n.name.ptr, len) != 0;
/* First, compare hashes to see what's what */
hash1 = NAMEISCACHED(&name1->n)
? ringHashBuf((const unsigned char *) name1->n.name.ptr, len)
: name1->n.name.hash;
hash2 = NAMEISCACHED(&name2->n)
? ringHashBuf((const unsigned char *) name2->n.name.ptr, len)
: name2->n.name.hash;
if (hash1 != hash2)
return 1;
/*
* At this point, we're 99% sure the names are the same, but
* we need to confirm...
* Load the first name. This may go into a cache, or the pktbuf.
*/
buf1 = ringPoolGetName(ringSetPool(set),
&name1->n,
(unsigned long *) &tlen);
if (!buf1)
return ringSetError(set)->error;
pgpAssert(tlen == len);
/* If name2 is available without using the pktbuf, great. */
if (NAMEISCACHED(&name2->n)) {
buf2 = name2->n.name.ptr;
return memcmp(buf1, buf2, len) != 0;
}
/*
* Otherwise, if name1 isn't in the pktbuf, we can fetch name2
* without fear of clobbering it.
*/
if (NAMEISCACHED(&name1->n)) {
pgpAssert(buf1 == name1->n.name.ptr);
buf2 = ringPoolGetName(ringSetPool(set),
&name2->n,
(unsigned long *) &tlen);
if (!buf2)
return ringSetError(set)->error;
pgpAssert(tlen == len);
return memcmp(buf1, buf2, len) != 0;
}
/* name1 is not cached, so it's in the pktbuf... */
pgpAssert(buf1 == ringSetPool(set)->pktbuf);
/*
* Otherwise, compare name1 in pktbuf to name2 on disk.
* Use MEMRING as dummy entry for file1; it is only used to
* make sure that any seeks which move its position get undone,
* and we don't care about that at this point.
*/
return namesdiffer(&ringSetPool(set)->files[MEMRINGBIT], name2);
}
/*
* Get a struct RingName on the given chain matching the one in the ring's
* pktbuf. 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 *
ringFindName(struct RingFile *file, union RingObject *parent)
{
struct RingPool *pool = file->set.pool;
union RingObject *name, **np, **pname=NULL;
size_t const len = pool->pktbuflen;
word32 hash;
int i;
char *buf; /* Used when trying to cache name */
hash = ringHashBuf((byte const *)pool->pktbuf, len);
pname = &parent->g.down;
for (np = &parent->g.down; (name=*np) != NULL; np = &name->g.next) {
/* Position name after names, key-sigs, sec's */
if (OBJISNAME(name) || OBJISSIG(name) || OBJISSEC(name))
pname = &name->g.next;
/* If not a name or wrong length, no match */
if (!OBJISNAME(name) || name->n.len != len)
continue;
/* If in memory, compare that */
if (NAMEISCACHED(&name->n)) {
if (memcmp(name->n.name.ptr, pool->pktbuf, len) == 0)
return name; /* Success */
} else {
if (name->n.name.hash == hash
&& (i = namesdiffer(file, name)) <= 0)
return i<0 ? NULL : name;
}
}
/* Failed to find a name - create one */
name = ringNewName(pool);
if (name) {
name->g.next = *pname;
*pname = name;
name->g.up = parent;
name->n.len = len;
name->n.name.hash = hash; /* May overwrite below */
/* Default new names to unknown trust */
name->n.trust = PGP_NAMETRUST_UNKNOWN;
#if PGPTRUSTMODEL>0
name->n.valid = name->n.validity = 0;
name->n.confidence = PGP_NEWTRUST_UNDEFINED;
NAMESETNEWTRUST(&name->n);
#endif
#if 1
/* You might want to disable this for MSDOS */
if (!(file->set.mask & MEMRINGMASK)) {
/* Don't "cache" in memring, it is for new creations */
buf = (char *)memPoolAlloc(&file->strings, len, 1);
if (buf) {
memcpy(buf, pool->pktbuf, len);
name->n.name.ptr = buf;
name->g.flags &= ~NAMEF_FILEMASK;
name->g.flags |= ringLsBitFind(file->set.mask);
NAMESETCACHED(&name->n);
}
}
#endif
}
return name;
}
/*
* Return 1 if the signature in the ring's pktbuf differs from the
* sig 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
sigsdiffer(struct RingFile *file1, union RingObject const *sig)
{
struct RingPool *pool = file1->set.pool;
struct RingFile *file2;
long retpos=0;
int i;
int bit;
/* Find a matching signature */
bit = ringLsBitFind(sig->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, sig->g.pos.fpos, SEEK_SET) != 0) {
ringErr(file2, sig->g.pos.fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
i = ringPacketDiffers(file2, sig, PKTBYTE_SIG, (word32)-1);
if (file2 == file1 && file1->f &&
pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
ringErr(file1, sig->g.pos.fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
return i;
}
static union RingObject *
ringFindSig(struct RingFile *file, union RingObject *parent)
{
struct RingPool *pool = file->set.pool;
union RingObject *key;
union RingObject *sig, **sigp, **fsigp;
int i;
/* Properties of the signature */
int err;
byte pkalg, keyID[8];
word32 tstamp;
word16 validity;
byte type;
byte hashalg;
byte version;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?