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

📄 pgpkeyadd.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 5 页
字号:
	PGPKeyDBObj *casig;
	PGPKeyDBObj *child;
	PGPKeyDBObj *gchild;
	PGPByte const *sigbuf;
	PGPSize siglen;
	PGPByte issuerbytes[8];
	PGPByte subjectbytes[8];
	PGPKeyID keyID;
	PGPByte pkalg;

	pgpAssert( OBJISTOPKEY( cakey ) );

	/* Find CA signature so we can get subject name */
	casig = NULL;
	for( child = cakey->down; IsntNull(child) && IsNull(casig);
		 child = child->next )
	{
		if( !pgpKeyDBObjIsReal( child ) )
			continue;
		if( OBJISSIG( child ) && pgpSigIsX509( child ) )
		{
			casig = child;
			break;
		}
		for( gchild = child->down; IsntNull(gchild); gchild=gchild->next )
		{
			if( !pgpKeyDBObjIsReal( gchild ) )
				continue;
			if( OBJISSIG( gchild ) && pgpSigIsX509( gchild ) )
			{
				casig = gchild;
				break;
			}
		}
	}

	/* Probably casig shouldn't be able to be null here */
	if( casig == NULL )
		return NULL;
			
	sigbuf = pgpFetchObject( casig, &siglen );
	sX509KeyIDBytes( kdb, sigbuf, siglen, NULL, issuerbytes, subjectbytes );

	pkalg = 0x80;
	pgpNewKeyIDFromRawData( subjectbytes, pkalg, 8, &keyID );
	pgpGetKeyByKeyID( kdb, &keyID, TRUE, FALSE, &x509key );

	return x509key;
}


/*
 * See if object matches the given buffer.  Ignores differences in header
 * tag/length formatting.
 */
	static PGPBoolean
sObjectMatchesBuffer( PGPKeyDBObj const *obj, PGPByte const *buf, PGPSize len )
{
	PGPByte const *objbuf;
	PGPSize objlen;
	PGPSize objheaderlen, bufheaderlen;
	PGPByte buftype, objtype;

	/* Skip buffer past header */
	buftype = PKTBYTE_TYPE(*buf);
	bufheaderlen = pgpPktBufferHeaderLen( buf );
	buf += bufheaderlen;
	len -= bufheaderlen;

	objbuf = pgpFetchObject( obj, &objlen );
	objtype = PKTBYTE_TYPE(*objbuf);
	if( objtype != buftype )
		return FALSE;

	/* Skip object past header */
	objheaderlen = pgpPktBufferHeaderLen( objbuf );
	objbuf += objheaderlen;
	objlen -= objheaderlen;
	return objlen == len && pgpMemoryEqual( objbuf, buf, len );
}


/* Look for a matching object with specified parent.  Allow deleteds. */
	PGPKeyDBObj *
pgpFindMatchingChild( PGPKeyDBObj *parent, PGPByte const *buf, PGPSize len )
{
	PGPKeyDBObj *obj;

	for( obj=parent->down; IsntNull( obj ); obj = obj->next )
	{
		if( sObjectMatchesBuffer( obj, buf, len ) )
			break;
	}
	return obj;
}


/* True if data in a pubkey buffer is consistent with data in a seckey
 * buffer.  If evidence of version bug, return *vbug as true.  The version
 * bug happens if the sec buffer says V3 and the pub buffer says V2.
 */
	static PGPBoolean
sConsistentPubAndSec( PGPByte const *pdata, PGPSize plen, PGPByte const *sdata,
	PGPSize slen, PGPBoolean *vbug )
{
	PGPSize secsublen;
	PGPSize secheaderlen;
	PGPSize pubheaderlen;
	PGPByte secver;
	PGPByte pubver;

	if( IsntNull( vbug ) )
		*vbug = FALSE;

	pgpAssert( PKTBYTE_TYPE(pdata[0]) == PKTBYTE_PUBKEY ||
			   PKTBYTE_TYPE(pdata[0]) == PKTBYTE_PUBSUBKEY);
	pgpAssert( PKTBYTE_TYPE(sdata[0]) == PKTBYTE_SECKEY ||
			   PKTBYTE_TYPE(sdata[0]) == PKTBYTE_SECSUBKEY);

	secsublen = pgpKeyParsePublicPrefix( sdata, slen );
	secheaderlen = pgpPktBufferHeaderLen( sdata );
	secver = sdata[secheaderlen];
	pubheaderlen = pgpPktBufferHeaderLen( pdata );
	pubver = pdata[pubheaderlen];

	/* Compare all but version byte.  Return false if that doesn't match */
	if( secsublen-secheaderlen != plen-pubheaderlen ||
		!pgpMemoryEqual( sdata+secheaderlen+1, pdata+pubheaderlen+1,
						 secsublen-secheaderlen-1 ) )
		return FALSE;

	/* Okay, they matched.  Now compare versions. */
	if( secver == pubver )
		return TRUE;

	/* Versions disagreed, check for version bug, else return false */
	if( secver == PGPVERSION_3 && pubver == PGPVERSION_2 )
	{
		*vbug = TRUE;
		return TRUE;
	}
	return FALSE;
}


/*
 * Create a public key buffer from a given private key buffer.  Pubkey
 * buffer must be freed.
 */
	PGPByte *
pgpKeyDBObjToPubData( PGPKeyDBObj *key, PGPSize *retlen )
{
	PGPKeyDB *			keydb;
	PGPContextRef		context;
	PGPByte const *		sdata;
	PGPByte *			pdata;
	PGPSize				slen;
	PGPSize				plen;
	PGPSize				secsublen;
	PGPSize				secheaderlen;
	PGPSize				pubheaderlen;
	PGPKeyInfo *		kinfo;
	PGPByte				pubpkttype;

	pgpAssert( OBJISKEY( key ) );
	pgpAssert( pgpKeyIsSec( key ) );
	keydb = PGPPeekKeyDBObjKeyDB( key );
	context = PGPPeekKeyDBContext( keydb );
	kinfo = pgpKeyToKeyInfo( key );

	sdata = pgpFetchObject( key, &slen );
	if( IsNull( sdata ) )
		return NULL;

	if( PKTBYTE_TYPE(sdata[0]) != PKTBYTE_SECKEY &&
		PKTBYTE_TYPE(sdata[0]) != PKTBYTE_SECSUBKEY )
	{
		/* This can happen if secret part is external, on a token */
		pgpAssert( PKTBYTE_TYPE(sdata[0]) == PKTBYTE_PUBKEY ||
				   PKTBYTE_TYPE(sdata[0]) == PKTBYTE_PUBSUBKEY );
		pdata = pgpContextMemAlloc( context, slen, 0 );
		if( IsNull( pdata ) )
			return NULL;
		pgpCopyMemory( sdata, pdata, slen );
		*retlen = slen;
		return pdata;
	}

	secsublen = pgpKeyParsePublicPrefix( sdata, slen );
	secheaderlen = pgpPktBufferHeaderLen( sdata );
	pubpkttype = (PKTBYTE_TYPE(sdata[0]) == PKTBYTE_SECKEY)? PKTBYTE_PUBKEY
														   : PKTBYTE_PUBSUBKEY;
	pubpkttype = PKTBYTE_BUILD( pubpkttype, 1 );
	pubheaderlen = pgpPktHeaderLen( pubpkttype, secsublen );
	plen = secsublen - secheaderlen + pubheaderlen;
	
	/* Allocate space for pub buffer */
	pdata = pgpContextMemAlloc( context, plen, 0 );
	if( IsNull( pdata ) )
		return NULL;
	
	/* Fill buffer */
	pgpPktHeaderPut( pdata, pubpkttype, secsublen-secheaderlen );
	pgpCopyMemory( sdata+secheaderlen, pdata+pubheaderlen,
				   secsublen-secheaderlen );
	
	/* Fix version bug */
	if( KEYHASVERSIONBUG(kinfo) )
		pdata[pubheaderlen] = PGPVERSION_2;

	*retlen = plen;
	return pdata;
}


PGPKeyDBObj *
pgpAddKey( PGPInt32 pkttype, PGPByte const *buf, PGPSize len,
	PGPKeyDB *kdb, PGPKeyDBObj *parent, PGPByte trusted, PGPError *outerr )
{
	PGPKeyDBObj *	key;
	PGPByte			pkalg;
	PGPByte			vpkalg;
	PGPUInt16		keybits;
	PGPByte			keyIDBytes[8];
	PGPByte			fp20n[20];
	PGPUInt32		tstamp;
	PGPUInt16		validity;
	PGPByte			v3;
	PGPBoolean		fSubkey;
	PGPBoolean		fSecret;
	PGPBoolean		fDummy;
	PGPByte const *	kdata;
	PGPSize			kdatalen;
	PGPKeyInfo *	kinfo;
	PGPBoolean		vbug;
	PGPKeyID		keyID;
	PGPError		err;

	fSubkey = (pkttype == PKTBYTE_PUBSUBKEY) || (pkttype == PKTBYTE_SECSUBKEY);
	fSecret = (pkttype == PKTBYTE_SECKEY) || (pkttype == PKTBYTE_SECSUBKEY);
	err = pgpKeyParse(kdb->context, buf, len, &pkalg, keyIDBytes,
					  fp20n, &keybits, &tstamp, &validity, &v3, fSecret );
	if( IsPGPError( err ) )
		return NULL;

	vpkalg = pkalg;			/* Viacrypt correction */
	if ((vpkalg | 1) == 3)
		vpkalg = 1;
	pgpNewKeyIDFromRawData( keyIDBytes, vpkalg, sizeof(keyIDBytes), &keyID );

	fSubkey = (pkttype == PKTBYTE_PUBSUBKEY) || (pkttype == PKTBYTE_SECSUBKEY);
	if( fSubkey ) {
		/* Subkey */
		pgpAssert( IsntNull( parent ) );
		pgpAssert( OBJISTOPKEY( parent ) );
	} else {
		pgpAssert( IsNull( parent ) );
	}

	/* Find the matching key structure */
	(void)pgpGetKeyByKeyID( kdb, &keyID, TRUE, TRUE, &key);

	fDummy = IsntNull( key ) && pgpKeyDBObjIsDummy( key );
	if( IsntNull( key ) && !fDummy ) {
		if( OBJISTOPKEY(key) == fSubkey )
		{
			/* Previous key and this key disagree on subkey-ness. Use prev. */
			/* Note that if prev is a subkey we will reject new userids
			 * as they can't go below subkeys.
			 */
			key->objflags &= ~kPGPKeyDBObjFlags_Deleted;
			return key;
		}
		/* Compare key with our data */
		kdata = pgpFetchObject( key, &kdatalen );
		if( !sObjectMatchesBuffer( key, buf, len ) )
		{
			/* Here what we are importing doesn't exactly match what we have */
			/* If previous was deleted, replace with new data */
			if( pgpKeyDBObjIsDeleted( key ) )
			{
				key->objflags &= ~kPGPKeyDBObjFlags_Deleted;
				goto fillin;
			}
			/* Else could just be a sec/pub disagreement */
			if( pkttype == PKTBYTE_TYPE(kdata[0]) )
			{
				/* No, that's not it, ignore new one */
				return key;
			}
			/* Here we disagree on sec/pub, see if they are otherwise same */
			if( fSecret )
			{
				pgpAssert( PKTBYTE_TYPE(kdata[0]) == PKTBYTE_PUBKEY ||
						   PKTBYTE_TYPE(kdata[0]) == PKTBYTE_PUBSUBKEY );
				if( !sConsistentPubAndSec( kdata, kdatalen, buf, len, &vbug ) )
				{
					/* Inconsistent, ignore new data */
					return key;
				}
				if( trusted && vbug )
				{
					kinfo = pgpKeyToKeyInfo( key );
					KEYSETVERSIONBUG( kinfo );
				}
				/* New sec data must replace pub */
				kinfo = pgpKeyToKeyInfo( key );
				kinfo->data = pgpNewObjData( kdb, buf, len );
				KEYSETSEC( kinfo );
			} else {
				pgpAssert( !fSecret );
				pgpAssert( PKTBYTE_TYPE(kdata[0]) == PKTBYTE_SECKEY  ||
						   PKTBYTE_TYPE(kdata[0]) == PKTBYTE_SECSUBKEY );
				if( !sConsistentPubAndSec( buf, len, kdata, kdatalen, &vbug ) )
				{
					/* Inconsistent, ignore new data */
					return key;
				}
				/* New pub data matches sec; record evidence of version bug */
				if( trusted && vbug )
				{
					kinfo = pgpKeyToKeyInfo( key );
					KEYSETVERSIONBUG( kinfo );
				}
			}
		} else {
			/* Match OK on key */
			key->objflags &= ~kPGPKeyDBObjFlags_Deleted;
		}
		return key;
	}
	if( fDummy ) {
		/* Key was a keyid only key */
		if( fSubkey && OBJISTOPKEY( key ) ) {
			/* Here we had a dummy top level key which turns out
			 * to be a subkey (can't happen unless subkeys sign) */
			/* Move it to proper position and mark as subkey. */
			pgpUnlinkKey( key, kdb );
			pgpLinkChild( key, parent );
			key->objflags &= ~kPGPKeyDBObjType_Key;
			key->objflags |= kPGPKeyDBObjType_SubKey;
		}
		key->objflags &= ~kPGPKeyDBObjFlags_Dummy;
		kinfo = pgpKeyToKeyInfo( key );
		/* Fix disagreement on pkalg for dummy key */
		if( kinfo->pkalg == kPGPPublicKeyAlgorithm_RSA &&
						pkalg == kPGPPublicKeyAlgorithm_RSASignOnly )
			kinfo->pkalg = kPGPPublicKeyAlgorithm_RSASignOnly;
		pgpAssert( kinfo->pkalg == pkalg );
		pgpAssert( pgpMemoryEqual( kinfo->keyID, keyIDBytes,
								   sizeof(keyIDBytes) ) );
	}
	if( IsNull( key ) ) {
		key = fSubkey ? sNewSubKey( kdb ) : sNewKey( kdb );
		if ( key == NULL )
		{
			err = kPGPError_OutOfMemory;
			goto error;
		}
		if( fSubkey ) {
			pgpLinkChild( key, parent );
		} else {
			pgpLinkKey( key, kdb );
		}
		kinfo = pgpKeyToKeyInfo( key );
		kinfo->pkalg = pkalg;
		pgpCopyMemory( keyIDBytes, kinfo->keyID, sizeof(keyIDBytes) );
		pgpLinkKeyToTree( key, kdb );
	}
 fillin:
	/* Fill in key data */
	kinfo = pgpKeyToKeyInfo( key );
	kinfo->fp20n = fp20n[0];
	kinfo->creationtime = tstamp;
	kinfo->validityperiod = validity;
	kinfo->keybits = keybits;
	kinfo->trust = 0;
	if (v3)
		KEYSETV3(kinfo);
	else
		KEYCLEARV3(kinfo);
	if( fSecret )
		KEYSETSEC(kinfo);
	else
		KEYCLEARSEC(kinfo);
	kinfo->data = pgpNewObjData( kdb, buf, len );
	return key;
 error:
	*outerr = err;
	return NULL;
}


PGPKeyDBObj *
pgpAddUserID( PGPInt32 pkttype, PGPByte const *buf, PGPSize len,
	PGPKeyDB *kdb, PGPKeyDBObj *parent, PGPError *outerr )
{
	PGPKeyDBObj *		name;
	PGPUserIDInfo *		uinfo;
	PGPError			err;

	(void)pkttype;
	pgpAssert( IsntNull( parent ) );
	if( !OBJISTOPKEY( parent ) )
		/* Can't add it */
		return NULL;

	/* Find the matching name structure */
	name = pgpFindMatchingChild( parent, buf, len );

	if( IsntNull( name ) ) {
		/* Got a match */
		if( name->objflags & kPGPKeyDBObjFlags_Deleted )
		{
			/* Bring back to life at end of list */
			name->objflags &= ~kPGPKeyDBObjFlags_Deleted;
			pgpUnlinkChild( name, parent );
			pgpLinkChild( name, parent );
		}
		return name;
	} else {
		name = sNewUserID( kdb );
		if ( name == NULL )
		{
			err = kPGPError_OutOfMemory;
			goto error;
		}
		uinfo = pgpUserIDToUserIDInfo( name );
		uinfo->validity = PGP_NEWTRUST_UNDEFINED;
		uinfo->confidence = PGP_NEWTRUST_UNDEFINED;
		pgpLinkChild( name, parent );
	}
	uinfo = pgpUserIDToUserIDInfo( name );
	if( pkttype == PKTBYTE_ATTRIBUTE )
		NAMESETATTR(uinfo);
	uinfo->data = pgpNewObjData( kdb, buf, len );
	return name;
 error:
	*outerr = err;
	return NULL;
}

PGPKeyDBObj *
pgpAddSig( PGPInt32 pkttype, PGPByte const *buf, PGPSize len,
	PGPKeyDB *kdb, PGPKeyDBObj *parent, PGPError *error )
{
	PGPKeyDBObj *		sig;
	PGPKeyDBObj *		key;
	PGPKeyDBObj *		tsig;
	PGPKeyInfo *		kinfo;
	PGPSigInfo *		sinfo;
	PGPByte				pkalg;
	PGPByte				vpkalg;
	PGPByte				keyidbytes[8];
	PGPByte				x509subjectkeyidbytes[8];
	PGPUInt32			tstamp;
	PGPUInt32			sigvalidity;
	PGPByte				type;
	PGPByte				hashalg;
	PGPSize				extralen;
	PGPByte				version;
	PGPBoolean			exportable;

⌨️ 快捷键说明

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