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

📄 pgpkeysig.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 3 页
字号:
													&handled, &changed,
													&verified);
					}
					if( IsPGPError( err ) )
						goto error;
					if( changed && IsntNull(changeSet) )
						PGPAddKey( key, changeSet );
					if( handled && IsntNull(func) )
					{
						err = func( arg, gchild, verified );
						if( IsPGPError( err ) )
							goto error;
					}
				}
			}
		}
	}
 error:
	return err;
}


/* Mark sig as unchecked */
	static void
sUncheckSig( PGPKeyDBObj *sig, PGPKeyDB *keydb, PGPBoolean *changed )
{
	PGPSigInfo *	sinfo;
	PGPByte			strust;

	*changed = FALSE;
	sinfo = pgpSigToSigInfo( sig );
	strust = sinfo->trust;
	strust &= ~PGP_SIGTRUSTF_CHECKED_TRIED;
	if( strust != sinfo->trust )
	{
		sinfo->trust = strust;
		pgpKeyDBIsDirty( keydb );
		*changed = TRUE;
	}
}


	PGPError
pgpCheckSig_internal( PGPKeyDBRef keydb, PGPKeyDBObj *sig,
	PGPKeyDBRef otherdb, PGPBoolean checkAll, PGPBoolean revocationonly,
	PGPBoolean *handled, PGPBoolean *changed, PGPBoolean *verified )
{
	PGPKeyDBObj *	signkey;
	PGPError		err = kPGPError_NoErr;

	*handled = FALSE;
	*changed = FALSE;
	*verified = FALSE;
	if( sCheckableSig( sig, otherdb, checkAll, revocationonly, &signkey ) )
	{
		if( IsNull( signkey ) )
		{
			sUncheckSig( sig, keydb, changed );
		} else {
			*handled = TRUE;
			err = sCheckSig( sig, signkey, changed, verified );
		}
	}
	return err;
}


/* Check sig */
	static PGPError
sCheckSig( PGPKeyDBObj *sig, PGPKeyDBObj *key, PGPBoolean *changed,
		   PGPBoolean *verified )
{
	PGPKeyInfo *	kinfo;
	PGPSigInfo *	sinfo;
	PGPKeyDB *		keydb;
	PGPKeyDB *		sigdb;
	PGPKeyDBObj *	parent;
	PGPKeyDBObj *	topkey;
	PGPKeyDBObj *	parentkey;
	PGPUserIDInfo *	uinfo;
	PGPContextRef	context;
	PGPByte			strust;
	PGPBoolean		sighashnew;
	PGPHashVTBL const *	hash;
	PGPHashContextRef	hashctx = NULL;
	PGPByte const *	buf;
	PGPByte const *	extrabuf;
	PGPSize			len;
	PGPSize			hlen;
	PGPSize			extralen;
	PGPError		err = kPGPError_NoErr;
	MemPool			cut;
    PGPMemoryMgrRef	mgr = NULL;

	pgpAssert( OBJISSIG( sig ) );
	pgpAssert( OBJISKEY( key ) );

	*changed = FALSE;
	*verified = FALSE;
	keydb = PGPPeekKeyDBObjKeyDB( key );
	sigdb = PGPPeekKeyDBObjKeyDB( sig );
	context = PGPPeekKeyDBContext( keydb );
	cut = *pgpPeekContextMemPool( context );
	mgr = pgpPeekContextMemPoolMgr( context );

	sinfo = pgpSigToSigInfo( sig );
	strust = sinfo->trust;     
	strust &= ~PGP_SIGTRUSTF_CHECKED_TRIED;

	/* If the superior object is a userid, reset the WARNONLY flag. */
	parent = sig->up;
	if( OBJISUSERID(parent) )
	{
		uinfo = pgpUserIDToUserIDInfo( parent );
		if( uinfo->oldvalidity & PGP_USERIDTRUSTF_WARNONLY) 
		{
			uinfo->oldvalidity &= ~PGP_USERIDTRUSTF_WARNONLY;
			pgpKeyDBIsDirty( sigdb );
		}
	}

	/* The new hash style includes the userid header and count */
	sighashnew =  sinfo->version > PGPVERSION_3;

	/* Special verification rules for X.509 signatures */
	if( SIGISX509(sinfo) ) {
		strust |= PGP_SIGTRUSTF_TRIED;
		if( pgpSigX509Valid (sig, key) )
			strust |= PGP_SIGTRUSTF_CHECKED;
		goto done;
	}

	hash = pgpHashByNumber( (PGPHashAlgorithm)sinfo->hashalg );
	if( IsNull( hash ) )
		goto done;

	/* Try to create our hash context */
	hashctx = pgpHashCreate( mgr, hash );
	if( IsNull( hashctx ) )
	{
		err = kPGPError_OutOfMemory;
		goto done;
	}

	if( IsPGPError( err = pgpHashObjParents( hashctx, sig->up, sighashnew ) ) )
		goto done;

	buf = pgpFetchObject(sig, &len);
	extrabuf = pgpSigParseExtra(buf, len, &extralen);

	strust |= PGP_SIGTRUSTF_TRIED;

	/*
	 * extralen != 5 legal only if sig is on key directly,
	 * or it is a new-format EXTENDED type.
	 */
	if( !OBJISTOPKEY(sig->up)					/* Sig directly on key */
		&& extralen != 5						/* Traditional case */
		&& sinfo->version <= PGPVERSION_3)		/* New format packets */
	{
		/* Not legal, set as failed */
		goto done;
	}

	/* Hash in extra bytes for signature */
	PGPContinueHash(hashctx, extrabuf, extralen);

	if( sighashnew )
	{
		/* Make sure hash can't match any old or doc hashes */
		PGPByte postscript[6];
		postscript[0] = PGPVERSION_4;	/* actually a 4! */
		postscript[1] = 0xff;			/* different from sig type */
		postscript[2] = (PGPByte)(extralen>>24);
		postscript[3] = (PGPByte)(extralen>>16);
		postscript[4] = (PGPByte)(extralen>> 8);
		postscript[5] = (PGPByte)(extralen>> 0);
		PGPContinueHash (hashctx, postscript, sizeof(postscript));
	}

	/* Ready for the actual sig check */
	hlen = pgpPktBufferHeaderLen( buf );
	err = pgpSigDataCheckBuf(buf+hlen, len-hlen, key, pgpHashFinal(hashctx));
	PGPFreeHashContext( hashctx );
	hashctx = NULL;
	if( err != 1 && err != 0 )
	{
		/* ViaCrypt self-signs encryption-only keys (as they're RSA,
		   it's possible), but we don't handle these.  Ignore this
		   type of signature. */
		if( pgpIsKeyRelatedError( err ) )
		{
			err = kPGPError_NoErr;
		}
		goto done;
	}
	if( err == 1 )
	{
		/* Success */
		strust |= PGP_SIGTRUSTF_CHECKED;
		/*
		 * On finding a valid self signature, apply any info in sig
		 * to parent key which goes there.  "key" is signer, topkey,
		 * is top level key above this sig, parentkey is closest
		 * key above this sig (may be a subkey).
		 */
		/* Find the top level key and the key which is above us */
		if( OBJISTOPKEY( sig->up ) )
		{
			topkey = sig->up;
			parentkey = topkey;
		} else {
			topkey = sig->up->up;
			if( OBJISSUBKEY( sig->up ) )
				parentkey = sig->up;
			else
				parentkey = topkey;
		}
		pgpAssert( OBJISTOPKEY( topkey ) );
		pgpAssert( OBJISKEY( parentkey ) );

		if( key == topkey ) {
			/* Self signature */
			PGPByte const *pk;
			/* Look for expiration date, apply to key above us */
			/* Note that this may alter the contents of buf */
			pk = pgpSigFindSubpacket (buf, SIGSUB_KEY_EXPIRATION,
				0, NULL, NULL, NULL, NULL, NULL);
			if( IsntNull(pk) ) {
				PGPUInt32 keyexp;
				keyexp = (PGPUInt32)
					((unsigned)pk[0]<<8|pk[1]) << 16 |
					((unsigned)pk[2]<<8|pk[3]);
				kinfo = pgpKeyToKeyInfo( parentkey );
				kinfo->validityperiod =
						(PGPUInt16)(keyexp/(24*3600));
			}
			/* Also check for primary userid sigs here */
			if( OBJISUSERID( parent ) )
			{
				if( !(sinfo->trust & PGP_SIGTRUSTF_CHECKED) &&
					(strust & PGP_SIGTRUSTF_CHECKED) )
				{
					/* A freshly validated self-sig */
					if( SIGISPRIMARYUID (sinfo) )
					{
						/* Clear any manual primary uid settings we had */
						pgpKeyClearPrimaryUserIDs( key, (PGPUInt32)-1 );
					}
				}
			}
		}
	}
	err = kPGPError_NoErr;
 done:
	*verified = (strust & PGP_SIGTRUSTF_CHECKED) != 0;
	if( sinfo->trust != strust )
	{
		pgpKeyDBIsDirty( sigdb );
		sinfo->trust = strust;
		*changed = TRUE;
	}

	if( IsntNull( hashctx ) )
		PGPFreeHashContext( hashctx );
	if( IsntNull( mgr ) )
		pgpContextMemPoolCutBack( context, &cut );
	return err;
}



/*
 * Update the hash context with the data in the object.
 *
 * hc		HashContext to update
 * obj		Object to update it with
 * hashuseridlength	If true, include the length of a userid packet in hash
 *			(this is the post-V3 sig convention)
 *
 * Return	0 on success, or an error code
 */
	PGPError
pgpHashObj (PGPHashContext *hc, PGPKeyDBObj *obj, PGPBoolean hashuseridlength)
{
	PGPKeyDB *keydb;
	PGPUserIDInfo *uinfo;
	PGPSize objlen;
	PGPSize hlen;
	PGPByte const *objbuf;
	PGPByte tmpbuf[5];
	PGPBoolean mustfree = FALSE;

	if( IsNull(hc) || IsNull(obj) )
		return kPGPError_BadParams;

	if( OBJISKEY(obj) && pgpKeyIsSec(obj) )
	{
		objbuf = pgpKeyDBObjToPubData( obj, &objlen );
		mustfree = TRUE;
	} else {
		objbuf = pgpFetchObject(obj, &objlen);
	}
	if( IsNull(objbuf) )
	{
		keydb = PGPPeekKeyDBObjKeyDB( obj );
		return pgpKeyDBError(keydb);
	}

	hlen = pgpPktBufferHeaderLen( objbuf );
	objbuf += hlen;
	objlen -= hlen;

	/* We use this format even for subkeys */
	if( OBJISKEY(obj) )
	{
		pgpAssert(objlen <= 65535);
		tmpbuf[0] = PKTBYTE_BUILD(PKTBYTE_PUBKEY, 1);
		tmpbuf[1] = (PGPByte)(objlen>>8);
		tmpbuf[2] = (PGPByte)objlen;
		PGPContinueHash(hc, tmpbuf, 3);
	} else if( OBJISUSERID(obj) && hashuseridlength ) {
		/*
		 * Use four bytes for userid length for future expansion.  Can't do
		 * it for keys due to backwards compatibility.
		 */
		uinfo = pgpUserIDToUserIDInfo( obj );
		tmpbuf[0] = NAMEISATTR(uinfo)
							? PKTBYTE_BUILD(PKTBYTE_ATTRIBUTE, 0)
							: PKTBYTE_BUILD(PKTBYTE_USERID, 0);
		tmpbuf[1] = (PGPByte)(objlen>>24);
		tmpbuf[2] = (PGPByte)(objlen>>16);
		tmpbuf[3] = (PGPByte)(objlen>> 8);
		tmpbuf[4] = (PGPByte)(objlen>> 0);
		PGPContinueHash(hc, tmpbuf, 5);
	}
	PGPContinueHash(hc, objbuf, objlen);
	if( mustfree )
		PGPFreeData( (PGPByte *)objbuf-hlen );
	return kPGPError_NoErr;
}


/*
 * Update the hash context with the data from the object and its parents
 */
	PGPError
pgpHashObjParents (PGPHashContext *hc, PGPKeyDBObj *obj,
		 PGPBoolean hashuseridlength)
{
	PGPKeyDBObj *	parents[3];
	PGPError		err;
	int				level;

	/* Trace object's parents up to top level */
	level = 0;
	for ( ; ; ) {
		pgpAssert ((unsigned)level < sizeof(parents)/sizeof(parents[0]));
		parents[level++] = obj;
		if( OBJISTOPKEY(obj) )
			break;
		obj = obj->up;
	}

	/* Hash downwards from top to object */
	while (--level >= 0) {
		err = pgpHashObj( hc, parents[level], hashuseridlength );
		if( IsPGPError( err ) ) {
			return err;
		}
	}
	return kPGPError_NoErr;
}

/*
 * Sign the specified object obj, along with its parents.
 * Place signature into newly allocated sig buffer.
 * sig buffer should be at least pgpMakeSigMaxSize(spec) bytes lon
 * Returns size of sig in bytes on success, negative on error.
 */
	PGPInt32
pgpSignObj(PGPKeyDBObj *obj, PGPSigSpec *spec, PGPByte **sig)
{
	PGPContextRef context;
	PGPHashContext *hc;
	PGPInt32 len;
	PGPError retval;
	PGPBoolean sighashnew;
	MemPool	cut;
	PGPMemoryMgrRef mgr = NULL;

	/* Initialize hash */
	context = PGPPeekKeyDBContext(PGPPeekKeyDBObjKeyDB( obj ) );
	cut = *pgpPeekContextMemPool( context );
	mgr = pgpPeekContextMemPoolMgr( context );
	hc = pgpHashCreate( mgr, pgpSigSpecHash(spec));
	if( IsNull(hc) )
	{
		pgpContextMemPoolCutBack( context, &cut );
		return kPGPError_BadHashNumber;
	}

	/* Use new hashing convention (include userid length) on new formats */
	sighashnew = pgpSigSpecVersion(spec) > PGPVERSION_3;

	retval = pgpHashObjParents( hc, obj, sighashnew );
	if( IsPGPError( retval ) )
	{
		PGPFreeHashContext(hc);
		pgpContextMemPoolCutBack( context, &cut );
		return (PGPInt32) retval;
	}

	/* Make the new sig */
	len = pgpMakeSig (spec, hc, sig);
	PGPFreeHashContext(hc);
	pgpContextMemPoolCutBack( context, &cut );
	return len;
}



/*
 * Local Variables:
 * tab-width: 4
 * End:
 * vi: ts=4 sw=4
 * vim: si
 */

⌨️ 快捷键说明

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