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

📄 cryptenv.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*						cryptlib Enveloping Routines						*
*					  Copyright Peter Gutmann 1996-2002						*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
  #include "envelope.h"
#else
  #include "envelope/envelope.h"
#endif /* Compiler-specific includes */

/* The default size for the envelope buffer and auxiliary buffer used as a
   staging area for assembling information.  Under DOS and Win16 they're
   smaller because of memory and int size limitations */

#if defined( __MSDOS16__ )
  #define DEFAULT_BUFFER_SIZE		8192
#elif defined( __WIN16__ )
  #define DEFAULT_BUFFER_SIZE		16384
#else
  #define DEFAULT_BUFFER_SIZE		32768
#endif /* OS-specific envelope size defines */
#define DEFAULT_AUXBUFFER_SIZE		8192

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Instantiate a cert chain from a collection of certs */

static int instantiateCertChain( const ENVELOPE_INFO *envelopeInfoPtr,
								 CONTENT_LIST *contentListItem )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	int status;

	/* Instantiate the cert chain.  Since this isn't a true cert chain (in 
	   the sense of being degenerate PKCS #7 SignedData) but only a 
	   context-tagged SET OF Certificate, we notify the cert management code 
	   of this when it performs the import */
	setMessageCreateObjectIndirectInfo( &createInfo, 
				envelopeInfoPtr->auxBuffer, envelopeInfoPtr->auxBufSize );
	createInfo.arg1 = CERTFORMAT_CERTSET;
	if( contentListItem->issuerAndSerialNumber == NULL )
		{
		createInfo.arg2 = CRYPT_IKEYID_KEYID;
		createInfo.strArg2 = contentListItem->keyID;
		createInfo.strArgLen2 = contentListItem->keyIDsize;
		}
	else
		{
		createInfo.arg2 = CRYPT_IKEYID_ISSUERANDSERIALNUMBER;
		createInfo.strArg2 = contentListItem->issuerAndSerialNumber;
		createInfo.strArgLen2 = contentListItem->issuerAndSerialNumberSize;
		}
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
								RESOURCE_IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
								&createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );
	contentListItem->iSigCheckKey = createInfo.cryptHandle;

	return( CRYPT_OK );
	}

/* Move the envelope component cursor */

static int moveCursor( ENVELOPE_INFO *envelopeInfoPtr, const int value )
	{
	if( envelopeInfoPtr->contentList == NULL )
		return( CRYPT_ERROR_NOTFOUND );	/* Nothing to move the cursor to */

	switch( value )
		{
		case CRYPT_CURSOR_FIRST:
			envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
			break;

		case CRYPT_CURSOR_PREVIOUS:
			if( envelopeInfoPtr->contentListCurrent == NULL || \
				envelopeInfoPtr->contentListCurrent == envelopeInfoPtr->contentList )
				return( CRYPT_ERROR_NOTFOUND );
			else
				{
				CONTENT_LIST *contentListPtr = envelopeInfoPtr->contentList;

				/* Find the previous element in the list */
				while( contentListPtr->next != envelopeInfoPtr->contentListCurrent )
					contentListPtr = contentListPtr->next;
				envelopeInfoPtr->contentListCurrent = contentListPtr;
				}
			break;

		case CRYPT_CURSOR_NEXT:
			if( envelopeInfoPtr->contentListCurrent == NULL || \
				envelopeInfoPtr->contentListCurrent->next == NULL )
				return( CRYPT_ERROR_NOTFOUND );
			envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentListCurrent->next;
			break;

		case CRYPT_CURSOR_LAST:
			envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
			while( envelopeInfoPtr->contentListCurrent->next != NULL )
				envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentListCurrent->next;
			break;

		default:
			return( CRYPT_ARGERROR_NUM1 );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Envelope Attribute Handling Functions				*
*																			*
****************************************************************************/

/* Handle data sent to or read from an envelope object */

static int processGetAttribute( ENVELOPE_INFO *envelopeInfoPtr,
								void *messageDataPtr, const int messageValue )
	{
	CRYPT_HANDLE iCryptHandle;
	MESSAGE_KEYMGMT_INFO getkeyInfo;
	CONTENT_LIST *contentListItem;
	int *valuePtr = ( int * ) messageDataPtr, status;

	/* Generic attributes are valid for all envelope types */
	if( messageValue == CRYPT_ATTRIBUTE_BUFFERSIZE )
		{
		*valuePtr = envelopeInfoPtr->bufSize;
		return( CRYPT_OK );
		}
	if( messageValue == CRYPT_ATTRIBUTE_ERRORTYPE )
		{
		*valuePtr = envelopeInfoPtr->errorType;
		return( CRYPT_OK );
		}
	if( messageValue == CRYPT_ATTRIBUTE_ERRORLOCUS )
		{
		*valuePtr = envelopeInfoPtr->errorLocus;
		return( CRYPT_OK );
		}

	/* If we're de-enveloping PGP data, make sure the attribute is valid for
	   PGP envelopes.  We can't perform this check via the ACLs because the
	   data type isn't known at envelope creation time, so there's a single
	   generic de-envelope type for which the ACLs allow the union of all
	   de-enveloping attribute types.  The following check weeds out the ones
	   which don't work for PGP */
	if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
		messageValue == CRYPT_ENVINFO_SIGNATURE_EXTRADATA )
		return( CRYPT_ARGERROR_VALUE );

	/* Make sure the attribute is valid for this envelope type and state */
	if( messageValue == CRYPT_ENVINFO_CURRENT_COMPONENT || \
		messageValue == CRYPT_ENVINFO_SIGNATURE_RESULT || \
		messageValue == CRYPT_ENVINFO_SIGNATURE || \
		messageValue == CRYPT_ENVINFO_SIGNATURE_EXTRADATA )
		{
		if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
			return( CRYPT_ARGERROR_OBJECT );

		/* The following check isn't strictly necessary since we can get some
		   information as soon as it's available, but it leads to less
		   confusion (for example without this check we can get signer info
		   long before we can get the signature results, which could be
		   misinterpreted to mean the signature is bad) and forces the caller
		   to do things cleanly */
		if( envelopeInfoPtr->usage == ACTION_SIGN && \
			envelopeInfoPtr->state != STATE_FINISHED )
			return( CRYPT_ERROR_INCOMPLETE );
		}
	else
		if( messageValue != CRYPT_ENVINFO_CONTENTTYPE && \
			messageValue != CRYPT_ENVINFO_DETACHEDSIGNATURE )
			return( CRYPT_ARGERROR_VALUE );

	/* If we're querying something which resides in the content list, make
	   sure there's a content list present.  If it's present but nothing is
	   selected, select the first entry */
	if( ( messageValue == CRYPT_ENVINFO_CURRENT_COMPONENT || \
		  messageValue == CRYPT_ENVINFO_SIGNATURE || \
		  messageValue == CRYPT_ENVINFO_SIGNATURE_RESULT || \
		  messageValue == CRYPT_ENVINFO_SIGNATURE_EXTRADATA ) && \
		envelopeInfoPtr->contentListCurrent == NULL )
		{
		if( envelopeInfoPtr->contentList == NULL )
			return( CRYPT_ERROR_NOTFOUND );
		envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
		}

	/* Handle the various information types */
	switch( messageValue )
		{
		case CRYPT_ENVINFO_CURRENT_COMPONENT:
			contentListItem = envelopeInfoPtr->contentListCurrent;

			/* If we need something other than a private key or we need a
			   private key but there's no keyset present to fetch it from,
			   just report what we need and exit */
			if( contentListItem->envInfo != CRYPT_ENVINFO_PRIVATEKEY || \
				envelopeInfoPtr->iDecryptionKeyset == CRYPT_ERROR )
				{
				*valuePtr = contentListItem->envInfo;
				return( CRYPT_OK );
				}

			/* There's a decryption keyset available, try and get the
			   required key from it.  Since we're accessing the key by 
			   (unique) key ID, there's no real need to specify a preference 
			   for encryption keys.

			   Unlike sig.check keyset access, we retry the access every 
			   time we're called because we may be talking to a device which 
			   has a trusted authentication path which is outside our 
			   control, so that the first read fails if the user hasn't 
			   entered their PIN but a second read once they've entered it 
			   will succeed */
			if( contentListItem->issuerAndSerialNumber == NULL )
				{
				setMessageKeymgmtInfo( &getkeyInfo, 
								( contentListItem->formatType == CRYPT_FORMAT_PGP ) ? \
								CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID, 
								contentListItem->keyID,
								contentListItem->keyIDsize, NULL, 0,
								KEYMGMT_FLAG_NONE );
				}
			else
				{
				setMessageKeymgmtInfo( &getkeyInfo, 
								CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
								contentListItem->issuerAndSerialNumber,
								contentListItem->issuerAndSerialNumberSize,
								NULL, 0, KEYMGMT_FLAG_NONE );
				}
			status = krnlSendMessage( envelopeInfoPtr->iDecryptionKeyset,
									  RESOURCE_IMESSAGE_KEY_GETKEY, &getkeyInfo, 
									  KEYMGMT_ITEM_PRIVATEKEY );

			/* If we managed to get the private key (either bcause it wasn't
			   protected by a password if it's in a keyset or because it came
			   from a device), push it into the envelope.  If the call
			   succeeds, this will import the session key and delete the
			   required-information list */
			if( cryptStatusOK( status ) )
				{
				status = envelopeInfoPtr->addInfo( envelopeInfoPtr,
												   CRYPT_ENVINFO_PRIVATEKEY,
												   &getkeyInfo.cryptHandle, 0 );
				krnlSendNotifier( getkeyInfo.cryptHandle,
								  RESOURCE_IMESSAGE_DECREFCOUNT );
				}

			/* If we got the key, there's nothing else needed.  If we didn't,
			   we still return an OK status since the caller is asking us for
			   the resource which is required and not the status of any
			   background operation which was performed while trying to obtain
			   it */
			*valuePtr = cryptStatusError( status ) ? \
							envelopeInfoPtr->contentListCurrent->envInfo : \
							CRYPT_ATTRIBUTE_NONE;
			return( CRYPT_OK );

		case CRYPT_ENVINFO_CONTENTTYPE:
			if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
				return( CRYPT_ERROR_NOTFOUND );
			*valuePtr = envelopeInfoPtr->contentType;
			return( CRYPT_OK );

		case CRYPT_ENVINFO_DETACHEDSIGNATURE:
			/* If this isn't signed data or we haven't sorted out the content
			   details yet, we don't know whether it's a detached sig or
			   not */
			if( envelopeInfoPtr->usage != ACTION_SIGN || \
				envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
				return( CRYPT_ERROR_NOTFOUND );
			*valuePtr = ( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) ? \
						TRUE : FALSE;
			return( CRYPT_OK );

		case CRYPT_ENVINFO_SIGNATURE_RESULT:
			/* Make sure the content list item is of the appropriate type,
			   and if we've already done this one don't process it a second
			   time.  This check is also performed by the addInfo() code, but
			   we duplicate it here to avoid having to do an unnecessary key
			   fetch for non-CMS signatures */
			contentListItem = envelopeInfoPtr->contentListCurrent;
			if( contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE )
				return( CRYPT_ERROR_NOTFOUND );
			if( contentListItem->processed )
				{
				*valuePtr = contentListItem->processingResult;
				return( CRYPT_OK );
				}

			/* If there's an encoded cert chain present and it hasn't been
			   instantiated as a cert object yet, instantiate it now.  We
			   don't check the return value since a failure isn't fatal, we
			   can still perform the sig.check with a user-supplied key */
			if( contentListItem->iSigCheckKey == CRYPT_ERROR && \
				envelopeInfoPtr->auxBuffer != NULL )
				instantiateCertChain( envelopeInfoPtr, contentListItem );

			/* If we don't have a sig.check key available (for example from a
			   CMS cert chain), make sure there's a keyset available to pull 
			   the key from and get the owner ID */
			if( contentListItem->iSigCheckKey == CRYPT_ERROR )
				{
				if( envelopeInfoPtr->iSigCheckKeyset == CRYPT_ERROR )
					{
					setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEYSET_SIGCHECK,
								  CRYPT_ERRTYPE_ATTR_ABSENT );
					return( CRYPT_ERROR_NOTINITED );
					}

				/* Try and get the key information.  Since we're accessing
				   the key by (unique) key ID, there's no real need to 
				   specify a preference for encryption keys */
				if( contentListItem->issuerAndSerialNumber == NULL )
					{
					setMessageKeymgmtInfo( &getkeyInfo, 
								( contentListItem->formatType == CRYPT_FORMAT_PGP ) ? \
								CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID, 
								contentListItem->keyID,
								contentListItem->keyIDsize, NULL, 0,
								KEYMGMT_FLAG_NONE );
					}
				else
					{
					setMessageKeymgmtInfo( &getkeyInfo,
								CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
								contentListItem->issuerAndSerialNumber,
								contentListItem->issuerAndSerialNumberSize,
								NULL, 0, KEYMGMT_FLAG_NONE );
					}
				status = krnlSendMessage( envelopeInfoPtr->iSigCheckKeyset,
							RESOURCE_IMESSAGE_KEY_GETKEY, &getkeyInfo, 
							KEYMGMT_ITEM_PUBLICKEY );
				if( cryptStatusError( status ) )
					return( status );
				iCryptHandle = getkeyInfo.cryptHandle;
				}

			/* Push the public key into the envelope, which performs the
			   signature check */
			*valuePtr = envelopeInfoPtr->addInfo( envelopeInfoPtr,
												  CRYPT_ENVINFO_SIGNATURE,
												  &iCryptHandle, 0 );
			if( contentListItem->iSigCheckKey == CRYPT_ERROR )
				/* If it's a newly-created key and it wasn't used, discard 
				   it */
				krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_DECREFCOUNT );
			return( CRYPT_OK );

		case CRYPT_ENVINFO_SIGNATURE:
			/* Return the key which was used to check the signature */
			if( envelopeInfoPtr->contentListCurrent == NULL )
				return( CRYPT_ERROR_NOTFOUND );
			if( envelopeInfoPtr->contentListCurrent->iSigCheckKey == CRYPT_ERROR )
				{
				/* There's no signing key present, try and instantiate it 
				   from an attached cert chain if there is one */
				if( envelopeInfoPtr->auxBuffer == NULL )
					return( CRYPT_ERROR_NOTFOUND );
				status = instantiateCertChain( envelopeInfoPtr, 
									envelopeInfoPtr->contentListCurrent );
				if( cryptStatusError( status ) )
					return( status );
				}
			iCryptHandle = envelopeInfoPtr->contentListCurrent->iSigCheckKey;

			/* Make the information externally visible */
			krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_INCREFCOUNT );
			krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
							 MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_INTERNAL );
			*valuePtr = iCryptHandle;
			return( CRYPT_OK );

		case CRYPT_ENVINFO_SIGNATURE_EXTRADATA:
			/* Make sure there's extra data present */
			iCryptHandle = envelopeInfoPtr->contentListCurrent->iExtraData;
			if( iCryptHandle == CRYPT_ERROR )
				return( CRYPT_ERROR_NOTFOUND );

			/* Make the information externally visible */
			krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_INCREFCOUNT );
			krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
							 MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_INTERNAL );
			*valuePtr = iCryptHandle;
			return( CRYPT_OK );
		}

	assert( NOTREACHED );
	return( CRYPT_ERROR );	/* Get rid of compiler warning */
	}

static int processGetAttributeS( ENVELOPE_INFO *envelopeInfoPtr,
								 void *messageDataPtr, const int messageValue )
	{
	CONTENT_LIST *contentListItem;
	int status;

⌨️ 快捷键说明

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