⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgpkeyadd.c

📁 PGP8.0源码 请认真阅读您的文件包然后写出其具体功能
💻 C
📖 第 1 页 / 共 5 页
字号:
/*____________________________________________________________________________
        Copyright (C) 2002 PGP Corporation
        All rights reserved.

		Add keydb objects to databases
		
        $Id: pgpKeyAdd.c,v 1.82 2002/08/06 20:11:00 dallen Exp $
____________________________________________________________________________*/
#include "pgpConfig.h"

#include <errno.h>
#include <stdio.h>
#include <string.h>

#include "pgpDebug.h"
#include "pgpPktByte.h"
#include "pgpKeyPriv.h"
#include "pgpHash.h"
#include "pgpKeySpec.h"
#include "pgpMem.h"
#include "pgpEnv.h"
#include "pgpErrors.h"
#include "pgpPubKey.h"
#include "pgpFile.h"
#include "pgpMakeSig.h"
#include "pgpSigSpec.h"
#include "pgpContext.h"
#include "pgpTrustPriv.h"
#include "pgpX509Priv.h"

#ifndef NULL
#define NULL 0
#endif


/* Simple link manipulations */

/* Link key last in keydb */
	static void
pgpLinkKey( PGPKeyDBObj *key, PGPKeyDB *kdb )
{
	PGPKeyDBObj *lastkey;

	if( IsNull( kdb->firstKeyInDB ) )
	{
		kdb->firstKeyInDB = key;
	} else {
		lastkey = kdb->lastKeyInDB;;
		if( IsNull( lastkey ) )
			lastkey = kdb->firstKeyInDB;
		while( IsntNull( lastkey->next ) )
			lastkey = lastkey->next;
		lastkey->next = key;
	}
	key->next = NULL;
	key->up = (PGPKeyDBObj *)kdb;		/* Overload up pointer as db pointer */
	kdb->lastKeyInDB = key;
}

	static void
pgpUnlinkKey( PGPKeyDBObj *key, PGPKeyDB *kdb )
{
	PGPKeyDBObj *prev;

	if( kdb->firstKeyInDB == key )
	{
		kdb->firstKeyInDB = key->next;
		key->next = NULL;
		return;
	}
	for( prev = kdb->firstKeyInDB; IsntNull(prev->next); prev=prev->next )
	{
		if( prev->next == key )
		{
			prev->next = key->next;
			key->next = NULL;
			return;
		}
	}
	pgpAssert( 0 );
}

/* link at end; put userids before subkeys, sigs before them */
	static void
pgpLinkChild( PGPKeyDBObj *child, PGPKeyDBObj *parent )
{
	PGPKeyDBObj **pnext;
	PGPBoolean isUserID;
	PGPBoolean isSig;

	/* Put sigs first, then userids, then subkeys */
	isUserID = pgpObjectType(child) == RINGTYPE_USERID;
	isSig = pgpObjectType(child) == RINGTYPE_SIG;

	/* pnext points at pointer to next sibling */
	for( pnext = &parent->down; IsntNull( *pnext ); pnext = &((*pnext)->next) )
	{
		PGPInt32 nexttype = pgpObjectType(*pnext);
		if( isSig && nexttype!=RINGTYPE_SIG )
			break;
		if( isUserID && nexttype!=RINGTYPE_SIG && nexttype!=RINGTYPE_USERID)
			break;
	}
		
	child->next = *pnext;
	*pnext = child;
	child->up = parent;
}


	static void
pgpUnlinkChild( PGPKeyDBObj *child, PGPKeyDBObj *parent )
{
	PGPKeyDBObj *prev;

	if( parent->down == child )
	{
		parent->down = child->next;
		child->next = NULL;
		child->up = NULL;
		return;
	}
	for( prev = parent->down; IsntNull(prev->next); prev=prev->next )
	{
		if( prev->next == child )
		{
			prev->next = child->next;
			child->next = NULL;
			child->up = NULL;
			return;
		}
	}
	pgpAssert(0);
}


	static PGPKeyDBObj *
sNewObj( PGPKeyDB *kdb, PGPSize infosize )
{
	PGPKeyDBObjInfo *info;
	PGPKeyDBObj *obj;
	MemPool cutback;

	cutback = kdb->objPool;
	obj = memPoolAlloc( &kdb->objPool, sizeof(PGPKeyDBObj), sizeof (void *) );
	if (IsNull( obj ) )
		goto outofmem;
	info = memPoolAlloc( &kdb->objPool, infosize, sizeof (void *) );
	if (IsNull( info ) )
		goto outofmem;
	pgpClearMemory( obj, sizeof(*obj) );
	pgpClearMemory( info, infosize );

	obj->magic = kPGPKeyDBObjMagic;
	obj->idinfo.info = info;
	return obj;
 outofmem:
	memPoolCutBack( &kdb->objPool, &cutback );
	pgpKeyDBSetError( kdb, kPGPError_OutOfMemory );
	return NULL;
}


	static PGPKeyDBObj *
sNewKey( PGPKeyDB *kdb )
{
	PGPKeyDBObj *key;

	key = sNewObj( kdb, sizeof(PGPKeyInfo) );
	if( IsNull( key ) )
		return NULL;
	key->objflags = kPGPKeyDBObjType_Key;
	return key;
}

	static PGPKeyDBObj *
sNewUserID( PGPKeyDB *kdb )
{
	PGPKeyDBObj *userid;

	userid = sNewObj( kdb, sizeof(PGPUserIDInfo) );
	if( IsNull( userid ) )
		return NULL;
	userid->objflags = kPGPKeyDBObjType_UserID;
	return userid;
}

	static PGPKeyDBObj *
sNewSig( PGPKeyDB *kdb )
{
	PGPKeyDBObj *sig;

	sig = sNewObj( kdb, sizeof(PGPSigInfo) );
	if( IsNull( sig ) )
		return NULL;
	sig->objflags = kPGPKeyDBObjType_Signature;
	return sig;
}

	static PGPKeyDBObj *
sNewSubKey( PGPKeyDB *kdb )
{
	PGPKeyDBObj *subkey;

	subkey = sNewObj( kdb, sizeof(PGPKeyInfo) );
	if( IsNull( subkey ) )
		return NULL;
	subkey->objflags = kPGPKeyDBObjType_SubKey;
	return subkey;
}

	static PGPKeyDBObj *
sNewCRL( PGPKeyDB *kdb )
{
	PGPKeyDBObj *crl;

	crl = sNewObj( kdb, sizeof(PGPCRLInfo) );
	if( IsNull( crl ) )
		return NULL;
	crl->objflags = kPGPKeyDBObjType_CRL;
	return crl;
}

	static PGPKeyDBObj *
sNewUnknown( PGPKeyDB *kdb )
{
	PGPKeyDBObj *unk;

	unk = sNewObj( kdb, sizeof(PGPUnkInfo) );
	if( IsNull( unk ) )
		return NULL;
	return unk;
}

/*
 * X.509 certs require some special handling.
 *
 * Ordinary PGP signatures are linked to their issuing key by the
 * keyid field (and algorithm byte).  We maintain the sigsby/nextby
 * linked list which links keys to the signatures they have issued.
 * When we add a new signature, we look for a key with that keyid,
 * and create a Dummy one if not found.  We then add the sig to the
 * sigsby list for that key.  When we add a new key, if it already
 * exists nothing happens; if a Dummy version exists then its sigsby
 * list already points at the signatures which have been issued by this
 * key, so we clear the Dummy flag; and if there is no key with this
 * keyid, that means that there have been no signatures issued by this
 * key, so we just create a new key object and its sigsby list is
 * empty.
 *
 * X.509 certificates are linked to their issuing certificate (note,
 * certificate not key) by the Issuer Name field.  This is a
 * structured list of textual subfields like Common Name,
 * Organizational Unit, etc.  This introduces several problems for us.
 * First, we want to look for keys by keyid, not a set of text fields.
 * Second, when we first read an X.509 CA key, we may not know its
 * Issuer Name field, not until we read its self-signed CA
 * certificate.  Theoretically that could happen at some later time.
 * Third, if we create a dummy key to represent the signer for X.509
 * certificates, this would probably be a different dummy key than the
 * one created as a dummy for PGP keys.
 *
 * To handle this, we look up X.509 keys by creating a keyid-like
 * field which is the hash of the Issuer Name.  Every X.509 issuer has
 * two key object entries, the real one, and an X.509 Dummy whose
 * keyid is this hash.  The X.509 Dummy is tagged as such, and
 * overloads its data field to point at the X.509 cert on the real
 * key.  (Theoretically, an X.509 issuer could have more than one
 * X.509 Dummy associated with it, if it had more than one cert with
 * different Issuer Names.)
 *
 * The basic mechanism of the X.509 Dummy solves our problems, as
 * follows.  When we import an X.509 certificate, we hash the Issuer
 * Name to produce the X.509 Dummy keyid and look up a key with that
 * ID.  (We also use a fake algorithm byte of 0x80.)  If found, we
 * then look at its data field to see if there is a real key that
 * corresponds, and use that if so.  (This last step is done in
 * GetKeyByKeyID.)  Otherwise we use the X.509 Dummy for the by field
 * of the sig, creating one if necessary.  This ensures that all X.509
 * certs issued by the same key will point at the same X.509 Dummy if
 * we don't have the issuing cert.
 *
 * Furthermore, when we import an X.509 certificate, the Subject Name
 * of the cert would be the Issuer Name used if the parent key issues
 * any certs of its own.  (In the case of a self-signed CA cert,
 * the Subject Name and Issuer Name are the same.)  So in addition
 * to the processing above, we also use the Subject Name of the cert
 * to look for and/or create an X.509 Dummy corresponding to the parent
 * key.  Keep in mind, this is for use of the parent key as an X.509
 * cert issuer.  The previous paragraph was with respect to finding
 * the key which issued this X.509 cert, this describes mechanism to
 * find certs issued by this X.509 key.
 *
 * Using the Issuer Name we create an X.509 Dummy keyid and look up or
 * create an X.509 Dummy key.  If found, we set its data field to
 * point at the cert on the issuing key.  Further, we move any keys
 * from the X.509 Dummy's sigsby list to the sigsby list of the parent
 * key, and change those sigs' by pointers to point to the parent key.
 * This way, once we have read the X.509 issuing key's certificate,
 * the issued certificates point at the issuing key.
 *
 */


/* Find fake X.509 keyid as hash of issuer and subject names */
/* Also return flag saying whether cert has a CRL distribution point */
	static PGPError
sX509KeyIDBytes( PGPKeyDB *kdb, PGPByte const *buf, PGPSize len,
	PGPBoolean *hasdpoint, PGPByte issuerkeyidbytes[8],
	PGPByte subjectkeyidbytes[8])
{
	PGPContextRef		context;
	PGPASN_XTBSCertificate *xtbscert;
	PGPByte const *		certbuf;
	PGPSize				certlen;
	PGPByte const *		issuername;
	PGPSize				issuerlen;
	PGPByte const *		subjectname;
	PGPSize				subjectlen;
	PGPByte const *		dpoint;
	PGPByte				hash[20];
	PGPError			err;

	(void) len;
	if( IsntNull( hasdpoint ) )
		*hasdpoint = FALSE;
	context = PGPPeekKeyDBContext( kdb );

	certbuf = pgpSigFindNAISubSubpacket (buf,
					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( context, certbuf, certlen, &xtbscert);
	if( IsPGPError( err ) )
		return err;
	issuername = xtbscert->issuer.val;
	issuerlen = xtbscert->issuer.len;
	subjectname = xtbscert->subject.val;
	subjectlen = xtbscert->subject.len;

	pgpFingerprint20HashBuf(context, issuername, issuerlen, hash);
	pgpCopyMemory( hash + sizeof(hash) - 8, issuerkeyidbytes, 8 );
	pgpFingerprint20HashBuf(context, subjectname, subjectlen, hash);
	pgpCopyMemory( hash + sizeof(hash) - 8, subjectkeyidbytes, 8 );

	if( IsntNull( hasdpoint ) )
	{
		dpoint =  pgpX509XTBSCertToDistPoint( xtbscert, NULL );
		if( dpoint != NULL ) {
			*hasdpoint = TRUE;
			PGPFreeData( (PGPByte *)dpoint );
		}
	}

	pgpX509FreeXTBSCert( context, xtbscert );
	return kPGPError_NoErr;
}


/* Having processed an X.509 sig, create or check for a dummy X509 key object
 * which will represent the "X.509 key id" of the key.  That is the
 * low 64 bits of the hash of the subject name.
 */
	static PGPError
sFixupX509ParentKey( PGPKeyDB *kdb, PGPKeyDBObj *sig,
	PGPByte x509subjectkeyidbytes[8] )
{
	PGPKeyDBObj *			key;
	PGPKeyDBObj *			x509key;
	PGPKeyInfo *			kinfo;
	PGPKeyInfo *			x509kinfo;
	PGPSigInfo *			sinfo;
	PGPSigInfo *			lastsiginfo = NULL;
	PGPKeyID				keyID;
	PGPByte					pkalg;

	key = sig;
	while( !OBJISTOPKEY( key ) )
		key = key->up;
	kinfo = pgpKeyToKeyInfo( key );

	/* Look up X.509 dummy key paired with this one */
	pkalg = 0x80;
	pgpNewKeyIDFromRawData( x509subjectkeyidbytes, pkalg, 8, &keyID );
	pgpGetKeyByKeyID( kdb, &keyID, TRUE, TRUE, &x509key );
	if( IsntNull( x509key ) )
	{
		/* If we have a real key this will already be pointing at it */
		if( !pgpKeyDBObjIsX509Dummy( x509key ) )
		{
			/*
			 * Ideally, at this point x509key is the same as key,
			 * and we are done.  It means that our key already has its
			 * paired dummy x509 key.  Conceivably it could be a
			 * different key, though.  That would mean that we have *
			 * two certs on different keys with the same subject name.
			 * This is unfortunate if one were to issue an X.509 certs
			 * itself, since there would be no way to know which one
			 * was the signer of such a cert.  We won't worry too much
			 * about that since it shouldn't happen in X.509 land and
			 * it won't cause any trouble if it doesn't happen.
			 */
/*			pgpAssert( x509key == key ); */
			return kPGPError_NoErr;
		}
		/*
		 * Here we have a dummy x509 entry.  This means that we have read
		 * one or more X.509 certs which used this key as the signer.
		 * They created this dummy entry and pointed their "by" pointers
		 * to it.  Now we must point this dummy to our real key, and
		 * move those sigs' "by" pointers to the real key too.
		 */
		/* Set paired data pointer */
		x509kinfo = pgpKeyToKeyInfo( x509key );
		pgpAssert( IsNull( x509kinfo->data ) );
		x509kinfo->data = (void *)sig;
		/* Fix "by" pointers in sigs */
		pgpAssert( IsntNull( x509kinfo->sigsby ) );
		for (sig = x509kinfo->sigsby; IsntNull(sig); sig = sinfo->nextby) {
			pgpAssert( OBJISSIG( sig ) );
			sinfo = pgpSigToSigInfo( sig );
			sinfo->by = key;
			lastsiginfo = sinfo;
		}
		/* Move sigs from x509kinfo->sigsby list to kinfo->sigsby list */
		lastsiginfo->nextby = kinfo->sigsby;
		kinfo->sigsby = x509kinfo->sigsby;
		x509kinfo->sigsby = NULL;
	} else {
		/*
		 * Here we need to create a dummy X.509 key entry which will
		 * be paired with our key and hold the alternate X509 keyid
		 * for our key.  */
		x509key = sNewKey( kdb );
		if( IsNull( key ) )
			return kPGPError_OutOfMemory;
		x509kinfo = pgpKeyToKeyInfo( x509key );
		pgpCopyMemory( x509subjectkeyidbytes, x509kinfo->keyID, 8 );
		x509kinfo->pkalg = pkalg;
		x509kinfo->data = (void *)sig;
		x509key->objflags |= kPGPKeyDBObjFlags_X509 | kPGPKeyDBObjFlags_Dummy;
		pgpLinkKey( x509key, kdb );
		pgpLinkKeyToTree( x509key, kdb );
	}
	return kPGPError_NoErr;
}

/*
 * Find paired CA key in another DB.  Will return X509 dummy unless a
 * "real" CA key exists in that DB.
 */
	PGPKeyDBObj *
pgpFindPairedX509Key( PGPKeyDBObj *cakey, PGPKeyDBRef kdb )
{
	PGPKeyDBObj *x509key;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -