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

📄 pgpkeyobj.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 5 页
字号:
 * first.  Then, we take the latest self signature on the primary userid
 * of the key and we see whether it has the subpacket of interest.
 * So there is one revocable self signature that counts, and it is the
 * latest one.  Plus, all the nonrevocable self sigs count.
 *
 * pmatches is filled in with the total
 * number of instances in all packets.  The plen, pcritical, phashed,
 * and pcreated values are filled in with the signature packet
 * corresponding to the nth instance of the data we want.
 *
 * key			key to use
 * subpacktype	subpacket type to search for
 * nth			nth matching subpacket to find
 * *plen		return length of data
 * *pcritical	return criticality field of subpacket
 * *phashed		return whether subpacket was in hashed region
 * *pcreation	return creation time of matching signature
 * *pmatches	return number of matches of this subpack type
 * *error		return error code
 *
 * Function returns pointer to the data, of length *plen, or NULL with *error
 * set for error code.  If matching packet is not found, return NULL
 * with *error = 0.
 */
	PGPByte const *
pgpKeyFindSubpacket (PGPKeyDBObj *obj, int subpacktype, unsigned nth,
	PGPSize *plen, PGPBoolean *pcritical, PGPBoolean *phashed,
	PGPUInt32 *pcreation, PGPUInt32 *pmatches, PGPError *error)
{
	PGPKeyDBObj		*sig, *bestsig, *lookobj, *signobj;
	PGPKeyDBObj		*child;
	PGPKeyDBObj		*primaryUserid;
	PGPSigInfo *	sinfo;
	PGPUInt32		bestcreation;
	PGPUInt32		totalmatches;
	PGPByte const	*bestp;
	PGPSize			bestlen;
	PGPBoolean		bestcritical;
	PGPBoolean		besthashed;
	int				level;

	pgpAssert(OBJISKEY(obj));

	signobj = OBJISTOPKEY(obj) ? obj : obj->up;
	primaryUserid = pgpKeyPrimaryUserID( signobj, 0 );
	
	bestlen = bestcritical = besthashed = bestcreation = 0;
	totalmatches = 0;
	sig = NULL;
	bestp = NULL;
	bestsig = NULL;

	if (error)
		*error = kPGPError_NoErr;

	/* First look for nonrevocable signatures */
	for (child = obj->down; IsntNull(child); child = child->next)
	{
		if( !pgpKeyDBObjIsReal( child ) )
			continue;
		/* Kludge here to look for sigs at either level 2 or level 3 */
		if( OBJISSIG( child ) )
		{
			sig = child;
			level = 2;
		} else {
			sig = child->down;
			level = 3;
		}
		/* This does one pass for level 2 sigs, or multiples for level 3 */
		for ( ; IsntNull( sig ) ; sig = (level == 2) ? NULL : sig->next )
		{
			/* Abort when we come to another key or subkey. */
			if (OBJISKEY(sig))
				goto done1;
			if( !OBJISSIG(sig))
				continue;
			if( !pgpKeyDBObjIsReal(sig) )
				continue;
			/* Only count self-sigs that have been validated */
			if (pgpSigMaker (sig) != signobj)
				continue;
			if ((pgpSigType (sig) & 0xf0) != PGP_SIGTYPE_KEY_GENERIC)
				continue;
			if (!pgpSigChecked (sig))
				continue;
			sinfo = pgpSigToSigInfo( sig );
			if (SIGISREVOCABLE(sinfo))
				continue;

			/* Here we have a nonrevocable self signature */
			*error = sFindSubpacket( sig, subpacktype, nth, &bestp, &bestlen,
									 &bestcritical, &besthashed, &bestcreation,
									 &totalmatches, &bestsig );
			if( IsPGPError( *error ) )
				return NULL;

			/* If don't need to count all matches, done now */
			if( IsNull( pmatches ) && IsntNull( bestsig ) )
				break;
		}
	}
done1:

	/* Second, on subkey, look below it; on key, look below primary */
	if( OBJISSUBKEY(obj) )
		lookobj = obj;
	else
		lookobj = primaryUserid;
	/* Only check if we don't have bestsig yet or we are returning matches */
	if (IsntNull(lookobj) && (IsNull(bestsig) || IsntNull(pmatches)))
	{
		sig = pgpLatestSigByKey( lookobj, signobj );
		if (sig)
		{
			sinfo = pgpSigToSigInfo( sig );
			if (SIGISREVOCABLE(sinfo))
			{
				*error = sFindSubpacket( sig, subpacktype, nth, &bestp,
										 &bestlen, &bestcritical, &besthashed,
										 &bestcreation, &totalmatches,
										 &bestsig );
				if( IsPGPError( *error ) )
					return NULL;
			}
		}
	}

	/* Third, look at other userids */
	/* Only check if we don't have bestsig yet or we are returning matches */
	if (IsntNull(lookobj) && (IsNull(bestsig) || IsntNull(pmatches)))
	{
		for (lookobj = signobj->down; IsntNull(lookobj); lookobj=lookobj->next)
		{
			if( !pgpKeyDBObjIsReal( lookobj ) )
				continue;
			if( !OBJISUSERID( lookobj ) )
				continue;
			if( lookobj == primaryUserid )
				continue;
			sig = pgpLatestSigByKey( lookobj, signobj );
			if (sig)
			{
				sinfo = pgpSigToSigInfo( sig );
				if (SIGISREVOCABLE(sinfo))
				{
					*error = sFindSubpacket( sig, subpacktype, nth, &bestp,
											 &bestlen, &bestcritical,
											 &besthashed, &bestcreation,
											 &totalmatches, &bestsig );
					if( IsPGPError( *error ) )
						return NULL;
				}
			}
			/* If don't need to count all matches, done now */
			if( IsNull( pmatches ) && IsntNull( bestsig ) )
				break;
		}
	}

	/* Fourth, check sigs directly below signing key */
	/* Only check if we don't have bestsig yet or we are returning matches */
	if( OBJISKEY( signobj )  &&  (IsNull(bestsig) || IsntNull(pmatches)))
	{
		lookobj = signobj;

		sig = pgpLatestSigByKey( lookobj, signobj );
		if (sig)
		{
			sinfo = pgpSigToSigInfo( sig );
			if (SIGISREVOCABLE(sinfo))
			{
				*error = sFindSubpacket( sig, subpacktype, nth, &bestp,
										 &bestlen, &bestcritical, &besthashed,
										 &bestcreation, &totalmatches,
										 &bestsig );
				if( IsPGPError( *error ) )
					return NULL;
			}
		}
	}

	if (plen)
		*plen = bestlen;
	if (pcritical)
		*pcritical = bestcritical;
	if (phashed)
		*phashed = besthashed;
	if (pcreation)
		*pcreation = bestcreation;
	if (pmatches)
		*pmatches = totalmatches;
	return bestp;
}


/*
 * Find an additional decryption key for the given key, if one exists.
 * nth tells which one to find.  *pkeys is set to the number of add'l
 * decryption keys, *pclass is set to the class byte associated with
 * the decryption key.  *pkalg and *keyid are set to the algorithm and
 * keyid of the nth ADK key.  Returns NULL but no error in *error if
 * the ADK key is not found.  Return *error as
 * kPGPError_ItemNotFound if there are fewer than n+1 ADKs.
 */
	PGPKeyDBObj *
pgpKeyAdditionalRecipientRequestKey (PGPKeyDBObj *obj,
	unsigned nth, PGPByte *pkalg, PGPKeyID *keyid,
	PGPByte *pclass, unsigned *pkeys, PGPError *error)
{
	PGPKeyDBObj	   *rkey;			/* Additional decryption key */
	PGPByte const  *krpdata;		/* Pointer to key decryption data */
	PGPSize			krdatalen;		/* Length of krdata */
	PGPBoolean		critical;		/* True if decryption field was critical */
	PGPBoolean		hashed;			/* True if was in hashed region */
	unsigned		matches;		/* Number of adk's found */
	PGPByte			fingerp[20];	/* Fingerprint of adk */
	PGPByte			krdata[22];		/* Copy of key decryption data packet */

	pgpAssert(OBJISKEY(obj));
	pgpAssert (error);

	*error	= kPGPError_NoErr;
	if( IsntNull( pkeys ) )
		*pkeys	= 0;
	if( IsntNull( pclass ) )
		*pclass	= 0;
	if( IsntNull( pkalg ) )
		*pkalg = 0;
	if( IsntNull( keyid ) )
	{
		pgpClearMemory( keyid, sizeof( *keyid ) );
	}
	
	krpdata = pgpKeyFindSubpacket (obj,
		SIGSUB_KEY_ADDITIONAL_RECIPIENT_REQUEST, nth, &krdatalen,
		&critical, &hashed, NULL, &matches, error);
	if (!krpdata  ||  !hashed) {
		if (IsntPGPError(*error))
			*error = kPGPError_ItemNotFound;
		return NULL;
	}
	/*
	 * krdata is 1 byte of class, 1 of pkalg, 20 bytes of fingerprint.
	 * Last 8 of 20 are keyid.  Make a copy because data is volatile when
	 * we do other operations.
	 */

	if (krdatalen < sizeof(krdata)) {
		/* malformed packet, can't use it */
		*error = kPGPError_ItemNotFound;
		return NULL;
	}
	pgpCopyMemory (krpdata, krdata, sizeof(krdata));

	/* Do we have ADK? */
	rkey = pgpKeyById8 (PGPPeekKeyDBObjKeyDB(obj), krdata[1],krdata+2+20-8);
	if (IsntNull (rkey)) {
		if( pgpKeyDBObjIsDummy( rkey ) ) {
			rkey = NULL;
		} else {
			pgpKeyFingerprint20 (rkey, fingerp);
			if (memcmp (fingerp, krdata+2, 20) != 0) {
				/* Have a key that matches in keyid but wrong fingerprint */
				rkey = NULL;
			}
		}
	}
	/* Success */
	if (pkeys) {
		*pkeys = matches;
	}
	if (pclass) {
		*pclass = krdata[0];
	}
	if (pkalg) {
		*pkalg = krdata[1];
	}
	if (keyid) {
		pgpNewKeyIDFromRawData( krdata+2+20-8, krdata[1], 8, keyid );
	}
	return rkey;
}

	
/*
 * Find a key revocation key and keyid for the given key.  nth tells
 * which one to find.  *pkeys is set to the number of key revocation
 * keys, *pclass is set to the class byte associated with the
 * revocation key.  Returns NULL but no error in *error if the ADK key
 * is not found.  Return *error as
 * kPGPError_ItemNotFound if there are fewer than n+1 ADKs.  The class
 * byte is intended for future expansion; for now the high order bit
 * is used to indicate a revocation authorization.  Later we could use
 * the other bits to authorize other kinds of signatures, perhaps.
 */
	PGPKeyDBObj *
pgpKeyRevocationKey (PGPKeyDBObj *obj, unsigned nth,
	PGPByte *pkalg, PGPKeyID *keyid, PGPByte *pclass, unsigned *pkeys,
	PGPError *error)
{
	PGPKeyDBObj	   *rkey;			/* Message revocation key */
	PGPByte const  *krpdata;		/* Pointer to key revocation data */
	PGPSize			krdatalen;		/* Length of krdata */
	PGPBoolean		critical;		/* True if revocation field was critical */
	PGPBoolean		hashed;			/* True if in hashed region (must be) */
	unsigned		matches;		/* Number of revkey packets found */
	PGPByte			fingerp[20];	/* Fingerprint of revkey */
	PGPByte			krdata[22];		/* Copy of key revocation data packet */

	pgpAssert(OBJISKEY(obj));
	pgpAssert (error);

	*error	= kPGPError_NoErr;
	if( IsntNull( pkeys ) )
		*pkeys	= 0;
	if( IsntNull( pclass ) )
		*pclass	= 0;
	if( IsntNull( pkalg ) )
		*pkalg = 0;
	if( IsntNull( keyid ) )
	{
		pgpClearMemory( keyid, sizeof( *keyid ) );
	}
	
	krpdata = pgpKeyFindSubpacket (obj, SIGSUB_KEY_REVOCATION_KEY, nth,
		&krdatalen, &critical, &hashed, NULL, &matches, error);
	if (!krpdata || !hashed) {
		if (IsntPGPError(*error))
			*error = kPGPError_ItemNotFound;
		return NULL;
	}
	/*
	 * krdata is 1 byte of class, 1 of pkalg, 20 bytes of fingerprint.
	 * Last 8 of 20 are keyid.  Make a copy because data is volatile when
	 * we do other operations.
	 */

	if (krdatalen < sizeof(krdata)) {
		/* malformed packet, can't use it */
		*error = kPGPError_ItemNotFound;
		return NULL;
	}
	pgpCopyMemory (krpdata, krdata, sizeof(krdata));

	/* Do we have revocation packet? */
	rkey = pgpKeyById8 (PGPPeekKeyDBObjKeyDB(obj), krdata[1],krdata+2+20-8);
	if (IsntNull (rkey) ) {
		if (pgpKeyDBObjIsDummy( rkey ) ) {
			rkey = NULL;
		} else {
			pgpKeyFingerprint20 (rkey, fingerp);
			if (memcmp (fingerp, krdata+2, 20) != 0) {
				/* Have a key that matches in keyid but wrong fingerprint */
				rkey = NULL;
			}
		}
	}
	/* Else success */
	if (pkeys) {
		*pkeys = matches;
	}
	if (pclass) {
		*pclass = krdata[0];
	}
	if (pkalg) {
		*pkalg = krdata[1];
	}
	if (keyid) {
		pgpNewKeyIDFromRawData( krdata+2+20-8, krdata[1], 8, keyid );
	}
	return rkey;
}


/*
 * Return true if rkey is a revocation key for key.
 * Includes case where rkey is a dummy key which has issued a signature
 * but is not local to the keyring.  In that case we just check for match
 * on keyid and pkalg.
 */
	PGPBoolean
pgpKeyIsRevocationKey (PGPKeyDBObj *key, PGPKeyDBObj *rkey)
{
	PGPByte				 revClass;
	PGPUInt32			 nRevKeys;
	PGPUInt32			 iRevKeys;
	PGPByte				 revAlg;
	PGPByte				 rKeyAlg;
	PGPKeyID			 revKeyID;
	PGPKeyID			 rKeyID;
	PGPBoolean			 nonLocal;
	PGPError			 error;

	nonLocal = pgpKeyDBObjIsDummy(rkey);
	if (nonLocal) {
		pgpKeyID8 (rkey, &rKeyAlg, &rKeyID);
	}

	nRevKeys = 1;
	iRevKeys = 0;
	while (iRevKeys < nRevKeys) {
		PGPKeyDBObj const *revkey;
		revkey = pgpKeyRevocationKey(key, iRevKeys++, &revAlg, &revKeyID,
									  &revClass, &nRevKeys, &error);
		if (IsPGPError(error))
			break;
		if (!(revClass & 0x80))
			continue;
		if (nonLocal) {
			if (rKeyAlg == revAlg &&
				0 == PGPCompareKeyIDs (&rKeyID, &revKeyID))
				return TRUE;
		} else if (revkey == rkey) {
			return TRUE;
		}
	}
	return FALSE;
}
	

/*
 * True if there is a third party revocation signature on the given
 * key.  Return the key (if local) and the keyid of the revoking key.
 * Note that this requires that there be both a revoking authorization
 * on the revoker key and a revocation issued by that key.
 */
	PGPBoolean
pgpKeyHasThirdPartyRevocation (PGPKeyDBObj *obj,
	PGPKeyDBObj **revkey, PGPByte *pkalg, PGPKeyID *keyid, PGPError *error)
{
	PGPSigInfo		*sinfo = NULL;
	PGPKeyDBObj		*topkey;
	PGPKeyDBObj		*sig;
	PGPByte			 rKeyAlg;
	PGPKeyID		 rKeyID;

	pgpAssert(OBJISKEY(obj));
	pgpAssert (error);

	*error	= kPGPError_NoErr;
	if( IsntNull( revkey ) )
		*revkey = NULL;
	if( IsntNull( pkalg ) )
		*pkalg = 0;
	if( IsntNull( keyid ) )
	{
		pgpClearMemory( keyid, sizeof( *keyid ) );
	}

	/* May be called on subkey, so find top level key */
	topkey = obj;
	if (OBJISSUBKEY(topkey))
		topkey = pgpKeyMasterkey (topkey );
	
	/* Search for a revocation signature on this key */
	for (sig=obj->down; IsntNull(sig); sig=sig->next) {
		if( !pgpKeyDBObjIsReal(sig) )
			continue;
		if (!OBJISSIG(sig))
			continue;
		sinfo = pgpSigToSigInfo( sig );
		if (sinfo->type != ( (topkey==obj) ? PGP_SIGTYPE_KEY_REVOKE
										   : PGP_SIGTYPE_KEY_SUBKEY_REVOKE ))
			continue;
		if (sinfo->by == topkey)
			continue;

		if (pgpKeyIsRevocationKey (topkey, sinfo->by))
			break;
	}

	if (IsNull (sig)) {
		/* No luck */
		return FALSE;
	}

	if( IsntNull( revkey ) ) {
		if( !pgpKeyDBObjIsDummy( sinfo->by ) )
			*revkey = sinfo->by;
	}

	pgpKeyID8 (sinfo->by, &rKeyAlg, &rKeyID);
	
	if (pkalg) {
		*pkalg = rKeyAlg;
	}
	if (keyid) {
		*keyid = rKeyID;
	}
	return TRUE;
}


/*
 * Create a SigSpec structure which represents the given signature.
 * We must have the signing key as a private key.  We would have to
 * change the initialization of pgpSigSpec to avoid this, but normally
 * the reason for doing this is to re-issue a modified signature, so it
 * is a reasonable restriction.
 */
	PGPSigSpec *
pgpSigSigSpec (PGPKeyDBObj *sig, PGPError *error)
{
	PGPContextRef cdkContext;
	PGPEnv *env;
	PGPSigInfo *sinfo;
	PGPByte *p;
	PGPSigSpec *spec;
	PGPSize len;
	PGPSize hlen;

	pgpAssert(OBJISSIG(sig));
	pgpAssert( IsntNull( error ) );
	*error = kPGPError_NoErr;

	sinfo = pgpSigToSigInfo( sig );
	cdkContext = PGPPeekKeyDBContext(PGPPeekKeyDBObjKeyDB( sig ) );
	env = pgpContextGetEnvironment( cdkContext );

	spec = pgpSigSpecCreate (env, sinfo->by, sinfo->type);
	if( IsNull( spec ) ) {
		*error = kPGPError_OutOfMemory;
		return NULL;
	}

	/* Fetch data for sig */
	p = (PGPByte *)pgpFetchObject(sig, &len);
	if( IsNull( p ) ) {
		pgpSigSpecDestroy (spec);
		*error = pgpKeyDBError( PGPPeekKeyDBObjKeyDB(sig) );
		return NULL;
	}

	hlen = pgpPktBufferHeaderLen( p );
	pgpSigSpecSetHashtype (spec, sinfo->hashalg);
	pgpSigSpecSetVersion (spec, p[hlen]);
	pgpSigSpecSetTimestamp (spec, sinf

⌨️ 快捷键说明

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