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

📄 env_cms.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*						cryptlib Enveloping Routines						*
*					  Copyright Peter Gutmann 1996-2003						*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "envelope.h"
  #include "asn1_rw.h"
  #include "asn1s_rw.h"
#elif defined( INC_CHILD )
  #include "envelope.h"
  #include "../misc/asn1_rw.h"
  #include "../misc/asn1s_rw.h"
#else
  #include "envelope/envelope.h"
  #include "misc/asn1_rw.h"
  #include "misc/asn1s_rw.h"
#endif /* Compiler-specific includes */

/* Determine the size of the envelope payload after PKCS #5 block padding if
   necessary.  This isn't just the size rounded up to the nearest multiple of 
   the block size since if the size is already a multiple of the block size, 
   it expands by another block, so we make the payload look one byte longer
   before rounding to the block size to ensure the one-block expansion */

#define paddedSize( size, blockSize )	\
		( ( blockSize > 1 ) ? roundUp( payloadSize + 1, blockSize ) : size )

#ifdef USE_ENVELOPES

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

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

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

static int checkHashAlgo( const CRYPT_ALGO_TYPE 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 FAR_BSS 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, OID_CMS_TSTOKEN },
	{ CRYPT_CONTENT_SPCINDIRECTDATACONTEXT, OID_MS_SPCINDIRECTDATACONTEXT },
	{ CRYPT_CONTENT_RTCSREQUEST, OID_CRYPTLIB_RTCSREQ },
	{ CRYPT_CONTENT_RTCSRESPONSE, OID_CRYPTLIB_RTCSRESP },
	{ CRYPT_CONTENT_RTCSRESPONSE_EXT, OID_CRYPTLIB_RTCSRESP_EXT },
	{ 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( contentOIDs[ 0 ].oid );	/* Get rid of compiler warning */
	}

/* Copy as much post-data state information (i.e. signatures) from the 
   auxiliary buffer to the main buffer as possible */

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

	/* Copy as much of the signature data as we can across */
	bytesCopied = min( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos,
					   envelopeInfoPtr->auxBufPos );
	if( bytesCopied < 1 || \
		bytesCopied > envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos )
		{
		/* Safety check */
		assert( NOTREACHED );
		return( CRYPT_ERROR_OVERFLOW );
		}
	memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
			envelopeInfoPtr->auxBuffer, bytesCopied );
	envelopeInfoPtr->bufPos += bytesCopied;

	/* Since we're in the post-data state, any necessary payload data 
	   segmentation has been completed.  However, the caller can't copy out 
	   any post-payload data because it's past the end-of-segment position.
	   In order to allow the buffer to be emptied to make room for new data
	   from the auxBuffer, we set the end-of-segment position to the end of
	   the new data */
	envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;

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

	return( dataLeft ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
	}

/* Write one or more indefinite-length end-of-contents indicators */

static int writeEOCs( ENVELOPE_INFO *envelopeInfoPtr, const int count )
	{
	static const BYTE indefEOC[ 16 ] = \
						{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
						  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
	const int dataLeft = envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos;
	const int eocLength = count * 2;

	if( dataLeft < eocLength )
		return( CRYPT_ERROR_OVERFLOW );
	memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos, indefEOC,
			eocLength );
	envelopeInfoPtr->bufPos += eocLength;
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Emit Content-Specific Headers						*
*																			*
****************************************************************************/

/* Write the header fields that encapsulate any enveloped data:

   SignedData/DigestedData */

static int writeSignedDataHeader( STREAM *stream,
								  const ENVELOPE_INFO *envelopeInfoPtr,
								  const BOOLEAN isSignedData )
	{
	const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
	ACTION_LIST *actionListPtr;
	long dataSize;
	int hashActionSize = 0;

	/* Determine the size of the hash actions */
	for( actionListPtr = envelopeInfoPtr->actionList; actionListPtr != NULL; 
		 actionListPtr = actionListPtr->next )
		hashActionSize += sizeofContextAlgoID( actionListPtr->iCryptHandle,
											   CRYPT_ALGO_NONE, 
											   ALGOID_FLAG_ALGOID_ONLY );

	/* Determine the size of the SignedData/DigestedData */
	if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED || \
		( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER ) )
		dataSize = CRYPT_UNUSED;
	else
		{
		/* Determine the size of the content OID + content */
		dataSize = ( envelopeInfoPtr->payloadSize ) ? \
			sizeofObject( sizeofObject( envelopeInfoPtr->payloadSize ) ) : 0;
		dataSize = sizeofObject( sizeofOID( contentOID ) + dataSize );

		/* Determine the size of the version, hash algoID, content, cert
		   chain, and signatures */
		dataSize = sizeofShortInteger( 1 ) + sizeofObject( hashActionSize ) + \
				   dataSize + envelopeInfoPtr->extraDataSize + \
				   sizeofObject( envelopeInfoPtr->signActionSize );
		}

	/* Write the SignedData/DigestedData header, version number, and SET OF
	   DigestInfo */
	writeCMSheader( stream, ( isSignedData ) ? \
					OID_CMS_SIGNEDDATA : OID_CMS_DIGESTEDDATA, dataSize, 
					FALSE );
	writeShortInteger( stream, 1, DEFAULT_TAG );
	writeSet( stream, hashActionSize );
	for( actionListPtr = envelopeInfoPtr->actionList; actionListPtr != NULL;
		 actionListPtr = actionListPtr->next )
		{
		int status = writeContextAlgoID( stream,
							actionListPtr->iCryptHandle, CRYPT_ALGO_NONE,
							ALGOID_FLAG_ALGOID_ONLY );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Write the inner Data header */
	return( writeCMSheader( stream, contentOID, envelopeInfoPtr->payloadSize, 
							TRUE ) );
	}

/* EncryptedContentInfo contained within EnvelopedData */

static int writeEncryptedContentHeader( STREAM *stream,
							const BYTE *contentOID,
							const CRYPT_CONTEXT iCryptContext,
							const long payloadSize, const long blockSize )
	{
	const long blockedPayloadSize = ( payloadSize == CRYPT_UNUSED ) ? \
						CRYPT_UNUSED : paddedSize( payloadSize, blockSize );

	return( writeCMSencrHeader( stream, contentOID, blockedPayloadSize,
								iCryptContext ) );
	}

/* EncryptedData, EnvelopedData */

static void writeEncryptionHeader( STREAM *stream, const BYTE *oid,
								   const int version, const long payloadSize,
								   const long blockSize, const long extraSize )
	{
	const long blockedPayloadSize = ( payloadSize == CRYPT_UNUSED ) ? \
						CRYPT_UNUSED : paddedSize( payloadSize, blockSize );

	writeCMSheader( stream, oid, 
					( payloadSize == CRYPT_UNUSED || extraSize == CRYPT_UNUSED ) ? \
						CRYPT_UNUSED : \
						sizeofShortInteger( 0 ) + extraSize + blockedPayloadSize,
					FALSE );
	writeShortInteger( stream, version, DEFAULT_TAG );
	}

static int writeEncryptedDataHeader( STREAM *stream,
									 const ENVELOPE_INFO *envelopeInfoPtr )
	{
	const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
	const int encrContentInfoSize = sizeofCMSencrHeader( contentOID,
			envelopeInfoPtr->payloadSize, envelopeInfoPtr->iCryptContext );

	if( cryptStatusError( encrContentInfoSize ) )
		return( encrContentInfoSize );

	/* Write the EncryptedData header and version number, and
	   EncryptedContentInfo header */
	writeEncryptionHeader( stream, OID_CMS_ENCRYPTEDDATA, 0,
				envelopeInfoPtr->payloadSize, envelopeInfoPtr->blockSize,
				encrContentInfoSize );
	return( writeEncryptedContentHeader( stream, contentOID,
				envelopeInfoPtr->iCryptContext, envelopeInfoPtr->payloadSize,
				envelopeInfoPtr->blockSize ) );
	}

static int writeEnvelopedDataHeader( STREAM *stream,
									 const ENVELOPE_INFO *envelopeInfoPtr )
	{
	const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
	const int encrContentInfoSize = sizeofCMSencrHeader( contentOID,
			envelopeInfoPtr->payloadSize, envelopeInfoPtr->iCryptContext );
	const int originatorInfoSize = envelopeInfoPtr->extraDataSize > 0 ? \
			( int ) sizeofObject( envelopeInfoPtr->extraDataSize ) : 0;

	if( cryptStatusError( encrContentInfoSize ) )
		return( encrContentInfoSize );

	/* Write the EnvelopedData header and version number and start of the SET
	   OF RecipientInfo/EncryptionKeyInfo */
	writeEncryptionHeader( stream, OID_CMS_ENVELOPEDDATA, 
				originatorInfoSize ? 2 : 0, envelopeInfoPtr->payloadSize, 
				envelopeInfoPtr->blockSize, 
				( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
					CRYPT_UNUSED : \
					sizeofObject( envelopeInfoPtr->cryptActionSize ) + \
						originatorInfoSize + encrContentInfoSize );
#ifdef USE_KEA
	if( originatorInfoSize > 0 )
		{
		int status;

		/* Write the wrapper for the originator info and the originator info 
		   itself */
		writeConstructed( stream, envelopeInfoPtr->extraDataSize, 0 );

		/* Export the originator cert chain either directly into the main 
		   buffer or into the auxBuffer if there's not enough room */
		if( originatorInfoSize >= sMemDataLeft( stream ) )
			{
			RESOURCE_DATA msgData;

			/* The originator chain is too big for the main buffer, we have
			   to write everything from this point on into the auxBuffer.  
			   This is then flushed into the main buffer in the calling code 
			   before anything else is written */
			stream = ( STREAM * ) &envelopeInfoPtr->auxStream;
			setMessageData( &msgData, envelopeInfoPtr->auxBuffer, 
							envelopeInfoPtr->auxBufSize );
			status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
									  IMESSAGE_CRT_EXPORT, &msgData,
									  CRYPT_ICERTFORMAT_CERTSET );
			if( cryptStatusOK( status ) )
				status = sSkip( stream, msgData.length );
			}
		else
			status = exportCertToStream( stream, 
										 envelopeInfoPtr->iExtraCertChain, 
										 CRYPT_ICERTFORMAT_CERTSET );
		if( cryptStatusError( status ) )
			return( status );
		}
#endif /* USE_KEA */

	return( ( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
			writeSetIndef( stream ) : \
			writeSet( stream, envelopeInfoPtr->cryptActionSize ) );
	}

/* AuthenticatedData */

static int writeAuthenticatedDataHeader( STREAM *stream,
							const ENVELOPE_INFO *envelopeInfoPtr )
	{
	const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
	const int macActionSize = \
				sizeofContextAlgoID( envelopeInfoPtr->actionList->iCryptHandle,
									 CRYPT_ALGO_NONE, ALGOID_FLAG_ALGOID_ONLY );

⌨️ 快捷键说明

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