📄 pgprngread.c
字号:
{
PGPByte const *buf = NULL;
PGPVirtMask secmask, bestfile; /* Needed in RINGTYPE_KEY */
PGPVirtMask notsecmask;
RingPool *pool = set->pool;
PGPByte pktbyte;
pgpVirtMaskInit (pool, &secmask);
pgpVirtMaskInit (pool, ¬secmask);
pgpVirtMaskInit (pool, &bestfile);
pgpAssert(pgpIsRingSetMember(set, obj));
pgpAssert(pgpVirtMaskIsOverlapping(&obj->g.mask, &pool->filemask));
switch (ringObjectType(obj)) {
case RINGTYPE_NAME:
buf = (PGPByte const *)ringPoolGetName(pool, &obj->n, lenp);
break;
case RINGTYPE_SIG:
buf = (PGPByte const *)ringFetchPacket(pool, obj, NULL, PKTBYTE_SIG,
RINGSIG_MAXLEN, lenp, ringSigVerify);
break;
case RINGTYPE_CRL:
buf = (PGPByte const *)ringFetchPacket(pool, obj, NULL, PKTBYTE_CRL,
RINGCRL_MAXLEN, lenp, ringCRLVerify);
break;
case RINGTYPE_UNK:
buf = (PGPByte const *)ringFetchPacket(pool, obj, NULL,
PKTBYTE_TYPE(obj->u.pktbyte),
RINGUNK_MAXLEN, lenp, ringUnkVerify);
break;
case RINGTYPE_SEC:
pktbyte = OBJISTOPKEY(obj->g.up) ? PKTBYTE_SECKEY :
PKTBYTE_SECSUBKEY;
buf = (PGPByte const *)ringFetchPacket(pool, obj, NULL,
pktbyte, RINGSEC_MAXLEN,
lenp, ringSecVerify);
/* Compensate for version bug */
if (buf
&& *lenp > 0
&& obj->g.flags & SECF_VERSION_BUG
&& buf[0] == PGPVERSION_3)
((PGPByte *)buf)[0] = PGPVERSION_2;
break;
case RINGTYPE_KEY:
/* File we'd like to fetch from */
pgpVirtMaskCopy (pool,
&(ringBestFile(pool, obj, 0)->set.mask), &bestfile);
/* Where secrets are located */
ringKeySecMask(pool, obj, &secmask);
/* Is where we want to fetch from secret? */
if (pgpVirtMaskIsOverlapping (&bestfile, &secmask)) {
pktbyte = OBJISTOPKEY(obj) ? PKTBYTE_SECKEY :
PKTBYTE_SECSUBKEY;
/* Have to fetch the secret key and extract. */
obj = obj->g.down;
while (!pgpVirtMaskIsOverlapping(&obj->g.mask, &bestfile)
|| !OBJISSEC(obj)) {
obj = obj->g.next;
pgpAssert(obj);
}
pgpVirtMaskCopy(pool, &secmask, ¬secmask);
pgpVirtMaskNOT(pool, ¬secmask, pool->nfiles);
buf = (PGPByte const *)ringFetchPacket(pool, obj,
¬secmask, pktbyte, RINGSEC_MAXLEN,
lenp, ringSecVerify);
if (buf) {
size_t len;
/* Compensate for version bug */
if (*lenp > 0
&& obj->g.flags & SECF_VERSION_BUG
&& buf[0] == PGPVERSION_3)
((PGPByte *)buf)[0] = PGPVERSION_2;
len = ringKeyParsePublicPrefix(buf, *lenp);
/* If unparseable, take the whole thing. */
if (len)
*lenp = len;
}
} else {
pktbyte = OBJISTOPKEY(obj) ? PKTBYTE_PUBKEY :
PKTBYTE_PUBSUBKEY;
/* Fetch public components */
buf = (PGPByte const *)ringFetchPacket(pool, obj, &secmask,
pktbyte, RINGKEY_MAXLEN,
lenp, ringKeyVerify);
}
break;
default:
pgpAssert(0);
break;
}
pgpVirtMaskCleanup (pool, &bestfile);
pgpVirtMaskCleanup (pool, &secmask);
pgpVirtMaskCleanup (pool, ¬secmask);
return buf;
}
/*** Various bookkeeping helper functions ***/
/*
* Sort all the keys in a pool into keyID order. This uses 8 passes
* of a byte-wise radix sort. Each pass is stable, so sorting on the
* least significant byte, proceeding to the most will result in a
* completely sorted list.
*
* Actually, it's sorted with the *visible* part (the low 32 bits) of the
* keyID more significant than the invisible part. This makes the ordering
* more sensible to a human watching what's going on.
*
* There are 256 lists, with a head and a tail pointer. The tail
* pointer is a pointer to a pointer, namely the slot the pointer to
* the next entry to be added to the list goes in. It is initialized
* to point to the head pointer. So adding an element to the list
* consists of setting *tail = object; and then tail = &object->next;
*
* After each pass, concatenate the lists, starting at the end.
* Begin with an empty list and keep appending the current list to
* the tail of the one before it, grabbing the head as the new
* current list.
*/
#if 0
static int
ringKeyIDcmp(PGPByte const id1[8], PGPByte const id2[8])
{
int i;
i = memcmp(id1+4, id2+4, 4);
return i ? i : memcmp(id1, id2, 4);
}
#endif
static void
ringSortKeys(RingPool *pool)
{
#if 1
/*
* Disable sort, users who switch back to old versions of
* PGP are unhappy to see their keyring reordered. The reason
* for the sort was to hide the order with which keys had been
* added to the keyring, and to make merges more efficient.
* For now neither of those is compelling enough to keep.
*/
(void)pool;
#else
int i, j;
int pass;
int lastpass;
union RingObject *list = pool->keys;
union RingObject *head[256];
union RingObject **tail[256];
for (pass=0; pass<9; ++pass) {
/* XXX Experimental backwards compat code - put DSA keys at end */
/* On last pass we sort by pkalg */
lastpass = (pass==8);
i = (pass < 4) ? (3-pass) : (11-pass); /* 3,2,1,0,7,6,5,4 */
/* Clear the table for the next distribution pass */
for (j = 0; j < 256; j++)
tail[j] = head+j;
/* Distribute the list elements among the sublists */
while (list) {
if (lastpass)
j = list->k.pkalg;
else
j = list->k.keyID[i];
*tail[j] = list;
tail[j] = &list->k.next;
list = list->k.next;
}
j = 256;
/* list is already 0 from the previous loop */
/* Gather the sublists back into one big list */
while (j--) {
*tail[j] = list;
list = head[j];
}
}
pool->keys = list;
#endif
}
static void
ringPoolLinkKey(RingPool *pool, union RingObject *parent,
union RingObject *key, PGPByte pkalg, PGPByte const keyID[8])
{
union RingObject **ptr;
pgpAssert(OBJISKEY(key));
pgpCopyMemory( keyID, key->k.keyID, 8 );
key->k.pkalg = pkalg;
if (parent) {
key->g.up = parent;
ptr = &parent->g.down;
while (*ptr)
ptr = &(*ptr)->g.next;
} else {
ptr = &pool->keys;
}
key->g.next = *ptr;
*ptr = key;
RINGPOOLHASHKEY(pool, key);
}
/* Remove specified key from the top-level keys list */
static void
ringPoolUnlinkKey(RingPool *pool, union RingObject *key)
{
union RingObject *obj, **objp;
pgpAssert(pool && key);
objp = &pool->keys;
while ((obj = *objp) != NULL && obj != key) {
objp = &obj->g.next;
}
pgpAssert(obj == key);
*objp = key->g.next;
key->g.next = NULL;
return;
}
/*
* Search for an X.509 key with the specified subject name.
* Return an X.509 signature which gives it that name.
* Calls ringFetchPacket, which may harm the pktbuf.
*/
union RingObject *
ringPoolFindX509NamedSig (RingPool *pool, PGPByte *name, PGPSize namelen)
{
PGPASN_XTBSCertificate *xtbscert;
RingObject *keys, *names, *sigs;
PGPByte *sigbuf;
PGPSize siglen;
PGPByte *certbuf;
PGPSize certlen;
PGPByte *subjectname;
PGPSize subjectlen;
PGPError err;
for (keys=pool->keys; keys; keys=keys->g.next) {
if (!OBJISTOPKEY(keys))
continue;
for (names=keys->g.down; names; names = names->g.next) {
if (!OBJISNAME(names))
continue;
for (sigs=names->g.down; sigs; sigs = sigs->g.next) {
if (OBJISSIG(sigs) && SIGISX509(&sigs->s)) {
sigbuf = (PGPByte *)ringFetchPacket (pool, sigs, NULL,
PKTBYTE_SIG, RINGSIG_MAXLEN, &siglen,
ringSigVerify);
/* Find subject name, compare with issuer name above */
certbuf = (PGPByte *)ringSigFindNAISubSubpacket (sigbuf,
SIGSUBSUB_X509, 0, &certlen, NULL, NULL, NULL, NULL);
pgpAssert( IsntNull( certbuf ) );
pgpAssert( certbuf[0] == SIGSUBSUB_X509 );
certbuf += 3;
certlen -= 3;
err = pgpX509BufferToXTBSCert( pool->context, certbuf,
certlen, &xtbscert);
if( IsPGPError( err ) )
continue;
subjectname = xtbscert->subject.val;
subjectlen = xtbscert->subject.len;
if (namelen == subjectlen &&
0 == memcmp (name, subjectname, namelen)) {
/* Have a match! */
pgpX509FreeXTBSCert( pool->context, xtbscert );
return sigs;
}
pgpX509FreeXTBSCert( pool->context, xtbscert );
}
}
}
}
/* No match */
return NULL;
}
/*
* Search for an X.509 key which signed this one. Information on the
* current key is in the pool->pktbuf.
*/
static union RingObject *
ringPoolFindDummyX509Key(RingPool *pool, RingFile *file)
{
PGPASN_XTBSCertificate *xtbscert;
PGPByte *issuername; /* issuer name subpart of cert */
PGPSize issuerlen;
PGPByte *pktcopy; /* copy of signature packet */
PGPSize pktlen;
PGPByte *certbuf;
PGPSize certlen;
PGPByte hash[20]; /* hash of issuer name */
PGPByte *keyid; /* faked-up keyid for dummy key */
RingObject *keys;
PGPUInt32 fpos; /* File pos */
PGPError err;
certbuf = (PGPByte *)ringSigFindNAISubSubpacket ((PGPByte *)pool->pktbuf,
SIGSUBSUB_X509, 0, &certlen, NULL, NULL, NULL, NULL);
pgpAssert (IsntNull( certbuf ) );
/* Skip type, version bytes */
pgpAssert (certbuf[0] == SIGSUBSUB_X509);
certbuf += 3;
certlen -= 3;
/* Find issuer name in cert */
err = pgpX509BufferToXTBSCert( pool->context, certbuf, certlen, &xtbscert);
if( IsPGPError( err ) )
return NULL;
issuername = xtbscert->issuer.val;
issuerlen = xtbscert->issuer.len;
/* Calculate hash of issuer name */
pgpFingerprint20HashBuf(pool->context, issuername, issuerlen, hash);
/*
* First look to see if we have a key with that keyid. We set this
* on dummy keys that we create.
*/
keyid = hash + sizeof(hash) - 8;
keys = ringPoolFindKey(pool, 0, keyid);
if (IsntNull( keys ) && pgpVirtMaskIsEmpty (&keys->g.mask)) {
pgpX509FreeXTBSCert( pool->context, xtbscert );
return keys;
}
/* Make a copy of the pktbuf area, we'll overwrite it */
pktlen = pool->pktbuflen;
pktcopy = (PGPByte *) pgpContextMemAlloc (pool->context,
pool->pktbuflen, 0);
if (IsNull (pktcopy)) {
pgpX509FreeXTBSCert( pool->context, xtbscert );
ringSimpleErr(pool, kPGPError_OutOfMemory);
return NULL;
}
pgpCopyMemory (pool->pktbuf, pktcopy, pktlen);
/* We may move our file pointer below */
fpos = pgpFileTell(file->f);
/* Search for an X.509 key with subject name equal to our issuer name */
/* Overwrites pktbuf */
keys = ringPoolFindX509NamedSig (pool, issuername, issuerlen);
pgpAssert (IsNull(keys) || OBJISSIG(keys));
if( IsntNull( keys ) ) {
while (!OBJISTOPKEY(keys))
keys = keys->g.up;
}
/* Here, if keys is non-NULL, we found a match */
/* Restore pool->pktbuf */
ringReserve (pool, pktlen);
pgpCopyMemory( pktcopy, pool->pktbuf, pktlen );
pool->pktbuflen = pktlen;
pgpContextMemFree (pool->context, pktcopy);
pgpFileSeek (file->f, fpos, SEEK_SET);
pgpX509FreeXTBSCert( pool->context, xtbscert );
if( IsNull( keys ) ) {
/* Must make dummy key, set keyid from hash of issuer name */
keys = ringNewKey(pool);
if (IsntNull (keys)) {
ringPoolLinkKey (pool, NULL, keys, 0, keyid);
}
}
return keys;
}
/*
* Same as ringPoolFindKey, but creates a dummy key with the given parent
* if one is not found.
* Note that a dummy key is a RingObject with its mask set to 0.
*/
static union RingObject *
ringPoolFindDummyKey(RingPool *pool, RingFile *file, RingObject *parent,
PGPByte pkalg, PGPByte const keyID[8], PGPBoolean isX509)
{
union RingObject *key;
if (isX509) {
pgpAssert (IsNull (parent));
key = ringPoolFindDummyX509Key (pool, file);
pgpAssert (IsntNull (key));
} else
key = ringPoolFindKey(pool, pkalg, keyID);
if (!key) {
key = ringNewKey(pool);
if (key) {
if (parent)
key->k.flags |= RINGOBJF_SUBKEY;
ringPoolLinkKey(pool, parent, key, pkalg, keyID);
}
}
return key;
}
/*
* Free an entire tree of objects.
* This does not do anything with the FilePos chain, but since the
* first entry is preallocated, if the object has at most one FilePos,
* (as is the case in newly created objects), no memory is leaked.
*/
static void
ringFreeTree(RingPool *pool, union RingObject *obj)
{
union RingObject *down;
if (!OBJISBOT(obj)) {
while ((down = obj->g.down) != NULL) {
obj->g.down = down->g.next;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -