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

📄 envelope.c

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

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "asn1.h"
  #include "asn1objs.h"
  #include "asn1oid.h"
  #include "envelope.h"
#elif defined( INC_CHILD )
  #include "../keymgmt/asn1.h"
  #include "../keymgmt/asn1objs.h"
  #include "../keymgmt/asn1oid.h"
  #include "../envelope/envelope.h"
#else
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1objs.h"
  #include "keymgmt/asn1oid.h"
  #include "envelope/envelope.h"
#endif /* Compiler-specific includes */

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

/* Check that a requested algorithm type is valid with enveloped data */

static int checkCryptAlgo( const CRYPT_ALGO cryptAlgo, 
						   const CRYPT_ALGO cryptMode )
	{
	return( checkAlgoID( cryptAlgo, cryptMode ) ? \
			CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
	}

static int checkHashAlgo( const CRYPT_ALGO hashAlgo )
	{
	return( checkAlgoID( hashAlgo, CRYPT_MODE_NONE ) ? \
			CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
	}

/* Get the OID for a CMS content type.  If no type is explicitly given, we
   assume raw data */

static const struct {
	const CRYPT_CONTENT_TYPE contentType;
	const BYTE *oid;
	} contentOIDs[] = {
	{ CRYPT_CONTENT_DATA, OID_CMS_DATA },
	{ CRYPT_CONTENT_SIGNEDDATA, OID_CMS_SIGNEDDATA },
	{ CRYPT_CONTENT_ENVELOPEDDATA, OID_CMS_ENVELOPEDDATA },
	{ CRYPT_CONTENT_SIGNEDANDENVELOPEDDATA, MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x04" ) },
	{ CRYPT_CONTENT_DIGESTEDDATA, OID_CMS_DIGESTEDDATA },
	{ CRYPT_CONTENT_ENCRYPTEDDATA, OID_CMS_ENCRYPTEDDATA },
	{ CRYPT_CONTENT_COMPRESSEDDATA, OID_CMS_COMPRESSEDDATA },
	{ CRYPT_CONTENT_TSTINFO, MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x01\x04" ) },
	{ CRYPT_CONTENT_SPCINDIRECTDATACONTEXT, OID_MS_SPCINDIRECTDATACONTEXT },
	{ 0, NULL }
	};

static const BYTE *getContentOID( const CRYPT_CONTENT_TYPE contentType )
	{
	int i;

	for( i = 0; contentOIDs[ i ].oid != NULL; i++ )
		if( contentOIDs[ i ].contentType == contentType )
			return( contentOIDs[ i ].oid );

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

/* Copy as much information from the auxiliary buffer to the main buffer as
   possible.  There are two variants of this function, one which copies
   straight from the auxiliary buffer, the second which synchronizes the
   auxStream status with the auxiliary buffer and then copies the data
   across */

int copyFromAuxBuffer( ENVELOPE_INFO *envelopeInfoPtr )
	{
	int bytesCopied, dataLeft;

	/* Copy as much as we can across */
	bytesCopied = min( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos,
					   envelopeInfoPtr->auxBufPos );
	memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
			envelopeInfoPtr->auxBuffer, bytesCopied );
	envelopeInfoPtr->bufPos += bytesCopied;

	/* If there's anything left, move it down in the buffer */
	dataLeft = envelopeInfoPtr->auxBufPos - bytesCopied;
	if( dataLeft )
		memmove( envelopeInfoPtr->auxBuffer, envelopeInfoPtr->auxBuffer + bytesCopied,
				 dataLeft );
	envelopeInfoPtr->auxBufPos = dataLeft;

	/* Rewind the memory stream to the new end of the data */
	sseek( &envelopeInfoPtr->auxStream, dataLeft );

	return( dataLeft );
	}

int copyFromAuxStream( ENVELOPE_INFO *envelopeInfoPtr )
	{
	int auxStreamSize = ( int ) stell( &envelopeInfoPtr->auxStream );

	if( sGetStatus( &envelopeInfoPtr->auxStream ) != CRYPT_OK )
		return( sGetStatus( &envelopeInfoPtr->auxStream ) );
	envelopeInfoPtr->auxBufPos = auxStreamSize;
	return( copyFromAuxBuffer( envelopeInfoPtr ) );
	}

/****************************************************************************
*																			*
*					Envelope Pre/Post-processing Functions					*
*																			*
****************************************************************************/

/* The following functions take care of pre/post-processing of envelope data
   during the enveloping process */

static int processKeyexchangeActions( ENVELOPE_INFO *envelopeInfoPtr )
	{
	CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
	ACTION_LIST *actionListPtr;
	BYTE originatorDomainParams[ CRYPT_MAX_HASHSIZE ];
	int totalSize, originatorDomainParamSize = 0, status;

	/* If there's an originator chain present, get the originator's domain 
	   parameters and if the key is tied to a device, get the device's handle
	   so we can create the session key object in it */
	if( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR )
		{
		RESOURCE_DATA msgData;

		setResourceData( &msgData, originatorDomainParams, 
						 CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( envelopeInfoPtr->iOriginatorChain,
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_IATTRIBUTE_DOMAINPARAMS );
		if( cryptStatusError( status ) )
			return( status );
		originatorDomainParamSize = msgData.length;
		status = krnlSendMessage( envelopeInfoPtr->iOriginatorChain, 
								  RESOURCE_IMESSAGE_GETDEPENDENT, &iCryptDevice,
								  OBJECT_TYPE_DEVICE );
		if( cryptStatusError( status ) )
			iCryptDevice = CRYPT_ERROR;
		}

	/* Create the session/MAC key if necessary */
	if( envelopeInfoPtr->actionList == NULL )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;
		int status;

		/* Create a default encryption action and add it to the action
		   list */
		setMessageCreateObjectInfo( &createInfo, 
							( envelopeInfoPtr->usage == ACTION_CRYPT ) ? \
								envelopeInfoPtr->defaultAlgo : \
								envelopeInfoPtr->defaultMAC );
		status = krnlSendMessage( ( iCryptDevice != CRYPT_ERROR ) ? \
								  iCryptDevice : SYSTEM_OBJECT_HANDLE,
								  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
								  &createInfo, OBJECT_TYPE_CONTEXT );
		if( cryptStatusOK( status ) )
			{
			status = krnlSendMessage( createInfo.cryptHandle, 
									  RESOURCE_IMESSAGE_CTX_GENKEY, 
									  NULL, FALSE );
			if( cryptStatusOK( status ) && \
				addAction( &envelopeInfoPtr->actionList,
						   envelopeInfoPtr->usage, 
						   createInfo.cryptHandle ) == NULL )
				status = CRYPT_ERROR_MEMORY;
			if( cryptStatusError( status ) )
				krnlSendNotifier( createInfo.cryptHandle, 
								  RESOURCE_IMESSAGE_DECREFCOUNT );
			}
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		{
		/* If the session key/MAC context is tied to a device, get its handle 
		   so we can check that all key exchange objects are also in the same 
		   device */
		status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle, 
								  RESOURCE_MESSAGE_GETDEPENDENT, 
								  &iCryptDevice, OBJECT_TYPE_DEVICE );
		if( cryptStatusError( status ) )
			iCryptDevice = CRYPT_ERROR;
		}

	/* Notify the kernel that the session key/MAC context is attached to the 
	   envelope.  This is an internal object used only by the envelope so we
	   tell the kernel not to increment its reference count when it attaches
	   it */
	krnlSendMessage( envelopeInfoPtr->objectHandle, 
					 RESOURCE_IMESSAGE_SETDEPENDENT, 
					 &envelopeInfoPtr->actionList->iCryptHandle, 
					 SETDEP_OPTION_NOINCREF );

	/* Now walk down the list of key exchange actions connecting each one to 
	   the session key action and evaluating their size */
	totalSize = 0;
	for( actionListPtr = envelopeInfoPtr->preActionList;
		 actionListPtr != NULL; actionListPtr = actionListPtr->next )
		{
		int cryptAlgo;

		/* If the session key/MAC context is tied to a device, make sure the 
		   key exchange object is in the same device */
		if( iCryptDevice != CRYPT_ERROR )
			{
			CRYPT_DEVICE iKeyexDevice;

			status = krnlSendMessage( actionListPtr->iCryptHandle, 
									  RESOURCE_MESSAGE_GETDEPENDENT, 
									  &iKeyexDevice, OBJECT_TYPE_DEVICE );
			if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
				return( CRYPT_ERROR_INVALID );
			}

		/* If it's a key agreement action, make sure there's originator info 
		   present and that the domain parameters match */
		if( actionListPtr->action == ACTION_KEYEXCHANGE_PKC && \
			cryptStatusOK( krnlSendMessage( actionListPtr->iCryptHandle, 
									RESOURCE_IMESSAGE_CHECK, NULL, 
									RESOURCE_MESSAGE_CHECK_PKC_KA_EXPORT ) ) )
			{
			RESOURCE_DATA msgData;
			BYTE domainParams[ CRYPT_MAX_HASHSIZE ];

			if( !originatorDomainParamSize )
				{
				setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_ORIGINATOR,
							  CRYPT_ERRTYPE_ATTR_ABSENT );
				return( CRYPT_ERROR_NOTINITED );
				}
			setResourceData( &msgData, domainParams, CRYPT_MAX_HASHSIZE );
			status = krnlSendMessage( actionListPtr->iCryptHandle,
									  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
									  &msgData, CRYPT_IATTRIBUTE_DOMAINPARAMS );
			if( cryptStatusError( status ) )
				return( status );
			if( ( originatorDomainParamSize != msgData.length ) || \
				memcmp( originatorDomainParams, domainParams, 
						originatorDomainParamSize ) )
				{
				setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_ORIGINATOR,
							  CRYPT_ERRTYPE_CONSTRAINT );
				return( CRYPT_ERROR_INVALID );
				}
			}

		/* Remember that we now have a controlling action and connect the
		   controller to the subject */
		envelopeInfoPtr->actionList->needsController = FALSE;
		actionListPtr->associatedAction = envelopeInfoPtr->actionList;

		/* Evaluate the size of the exported action.  If it's a conventional 
		   key exchange, we force the use of the CMS format since there's no 
		   reason to use the cryptlib format.  Even though it's not required 
		   for encoding the length for DLP-based PKC's, we still evaluate it 
		   anyway to check that everything will be OK later on */
		status = iCryptExportKeyEx( NULL, &actionListPtr->encodedSize,
						( actionListPtr->action == ACTION_KEYEXCHANGE ) ? \
							CRYPT_FORMAT_CMS : envelopeInfoPtr->type,
						envelopeInfoPtr->actionList->iCryptHandle,
						actionListPtr->iCryptHandle, 
						( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR ) ? \
							envelopeInfoPtr->iOriginatorChain : CRYPT_UNUSED );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( actionListPtr->iCryptHandle, 
									  RESOURCE_IMESSAGE_GETATTRIBUTE, 
									  &cryptAlgo, CRYPT_CTXINFO_ALGO );
		if( cryptStatusError( status ) )
			return( status );
		if( cryptAlgo == CRYPT_ALGO_ELGAMAL )
			/* If there are any key exchange actions which will result in
			   indefinite-length encodings present, we can't use a definite-
			   length encoding for the key exchange actions */
			totalSize = CRYPT_UNUSED;
		else
			if( totalSize != CRYPT_UNUSED )
				totalSize += actionListPtr->encodedSize;
		}
	envelopeInfoPtr->cryptActionSize = totalSize;

	return( CRYPT_OK );	
	}

static int preEnvelopeEncrypt( ENVELOPE_INFO *envelopeInfoPtr )
	{
	/* If there's originator info present, find out what it'll take to encode
	   it into the envelope header */
	if( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR )
		{
		RESOURCE_DATA msgData;
		int status;

		/* Determine how big the originator cert chain will be */
		setResourceData( &msgData, NULL, 0 );
		status = krnlSendMessage( envelopeInfoPtr->iOriginatorChain,
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
								  CRYPT_IATTRIBUTE_CERTSET );
		if( cryptStatusError( status ) )
			return( status );
		envelopeInfoPtr->extraDataSize = msgData.length;

		/* If we have very long originator cert chains the auxBuffer may not 
		   be large enough to contain the resulting chain, so we have to 
		   expand it to handle the chain */
		if( envelopeInfoPtr->auxBufSize < envelopeInfoPtr->extraDataSize + 64 )
			{
			free( envelopeInfoPtr->auxBuffer );
			if( ( envelopeInfoPtr->auxBuffer = \
					malloc( envelopeInfoPtr->extraDataSize + 64 ) ) == NULL )
				return( CRYPT_ERROR_MEMORY );
			envelopeInfoPtr->auxBufSize = envelopeInfoPtr->extraDataSize + 64;
			}
		}

	/* If there are key exchange actions, connect them to the session key/MAC
	   action */
	if( envelopeInfoPtr->preActionList != NULL )
		{
		int status;

		status = processKeyexchangeActions( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	return( CRYPT_OK );
	}

static int preEnvelopeSign( ENVELOPE_INFO *envelopeInfoPtr )
	{
	ACTION_LIST *actionListPtr;
	int largestSignatureSize = 0, status;

	/* If we're generating a detached signature, the content is supplied
	   externally and has zero size */
	if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
		envelopeInfoPtr->payloadSize = 0;

	/* Evaluate the size of each signature action */
	for( actionListPtr = envelopeInfoPtr->postActionList; actionListPtr != NULL;
		 actionListPtr = actionListPtr->next )
		{
		int cryptAlgo, signatureSize, signingAttributes;

		/* If it's a CMS envelope we have to write the signing cert chain
		   alongside the signatures as extra data unless it's explicitly 
		   excluded, so we record how large the info will be for later.  In 
		   addition we have to match the content-type in the authenticated 
		   attributes with the signed content type if it's anything other 
		   than 'data' (the data content-type is added automatically) */
		if( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
			envelopeInfoPtr->type == CRYPT_FORMAT_SMIME )
			{
			RESOURCE_DATA msgData;

			/* Determine how big the cert chain will be unless we're 
			   explicitly not including signing certs */
			if( !( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) )
				{
				setResourceData( &msgData, NULL, 0 );
				status = krnlSendMessage( actionListPtr->iCryptHandle,
								RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
								CRYPT_IATTRIBUTE_CERTSET );
				if( cryptStatusError( status ) )
					return( status );
				envelopeInfoPtr->extraDataSize += msgData.length;
				if( msgData.length > largestSignatureSize )
					largestSignatureSize = msgData.length;
				}

			/* If there's no content-type present and the signed content
			   type isn't 'data' or it's an S/MIME envelope, create signing
			   attributes to hold the content-type and smimeCapabilities.
			   Then, make sure that the content-type in the attributes
			   matches the actual content type */
			if( actionListPtr->iExtraData == CRYPT_ERROR && \
				( envelopeInfoPtr->contentType != CRYPT_CONTENT_DATA || \
				  envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) )
				{

⌨️ 快捷键说明

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