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

📄 cms_env.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*						cryptlib CMS Enveloping Routines					*
*					    Copyright Peter Gutmann 1996-2008					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "envelope.h"
  #include "asn1.h"
  #include "asn1_ext.h"
#else
  #include "envelope/envelope.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.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( size + 1, blockSize ) : size )

#ifdef USE_ENVELOPES

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

/* Sanity-check the envelope state */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN sanityCheck( const ENVELOPE_INFO *envelopeInfoPtr )
	{
	assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	/* Make sure that general envelope state is in order */
	if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
		return( FALSE );
	if( envelopeInfoPtr->envState < ENVSTATE_NONE || \
		envelopeInfoPtr->envState >= ENVSTATE_LAST )
		return( FALSE );

	/* Make sure that the buffer position is within bounds */
	if( envelopeInfoPtr->buffer == NULL || \
		envelopeInfoPtr->bufPos < 0 || \
		envelopeInfoPtr->bufPos > envelopeInfoPtr->bufSize || \
		envelopeInfoPtr->bufSize < MIN_BUFFER_SIZE || \
		envelopeInfoPtr->bufSize >= MAX_INTLENGTH )
		return( FALSE );

	/* If the auxBuffer isn't being used, make sure that all values related 
	   to it are clear */
	if( envelopeInfoPtr->auxBuffer == NULL )
		{
		if( envelopeInfoPtr->auxBufPos != 0 || \
			envelopeInfoPtr->auxBufSize != 0 )
			return( FALSE );

		return( TRUE );
		}

	/* Make sure that the auxBuffer position is within bounds */
	if( envelopeInfoPtr->auxBufPos < 0 || \
		envelopeInfoPtr->auxBufPos > envelopeInfoPtr->auxBufSize || \
		envelopeInfoPtr->auxBufSize < 0 || \
		envelopeInfoPtr->auxBufSize >= MAX_INTLENGTH )
		return( FALSE );

	return( TRUE );
	}

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

CHECK_RETVAL_BOOL \
BOOLEAN cmsCheckAlgo( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
					  IN_MODE_OPT const CRYPT_MODE_TYPE cryptMode )
	{
	REQUIRES_B( cryptAlgo > CRYPT_ALGO_NONE && \
				cryptAlgo < CRYPT_ALGO_LAST );
	REQUIRES_B( ( cryptMode == CRYPT_MODE_NONE ) || \
				( cryptMode > CRYPT_MODE_NONE && \
				  cryptMode < CRYPT_MODE_LAST ) );

	return( checkAlgoID( cryptAlgo, cryptMode ) );
	}

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

static const OID_INFO FAR_BSS contentOIDs[] = {
	{ OID_CMS_DATA, CRYPT_CONTENT_DATA },
	{ OID_CMS_SIGNEDDATA, CRYPT_CONTENT_SIGNEDDATA },
	{ OID_CMS_ENVELOPEDDATA, CRYPT_CONTENT_ENVELOPEDDATA },
	{ MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x04" ), CRYPT_CONTENT_SIGNEDANDENVELOPEDDATA },
	{ OID_CMS_DIGESTEDDATA, CRYPT_CONTENT_DIGESTEDDATA },
	{ OID_CMS_ENCRYPTEDDATA, CRYPT_CONTENT_ENCRYPTEDDATA },
	{ OID_CMS_COMPRESSEDDATA, CRYPT_CONTENT_COMPRESSEDDATA },
	{ OID_CMS_AUTHDATA, CRYPT_CONTENT_AUTHDATA },
	{ OID_CMS_AUTHENVDATA, CRYPT_CONTENT_AUTHENVDATA },
	{ OID_CMS_TSTOKEN, CRYPT_CONTENT_TSTINFO },
	{ OID_MS_SPCINDIRECTDATACONTEXT, CRYPT_CONTENT_SPCINDIRECTDATACONTEXT },
	{ OID_CRYPTLIB_RTCSREQ, CRYPT_CONTENT_RTCSREQUEST },
	{ OID_CRYPTLIB_RTCSRESP, CRYPT_CONTENT_RTCSRESPONSE },
	{ OID_CRYPTLIB_RTCSRESP_EXT, CRYPT_CONTENT_RTCSRESPONSE_EXT },
	{ MKOID( "\x06\x06\x67\x81\x08\x01\x01\x01" ), CRYPT_CONTENT_MRTD },
	{ NULL, 0 }, { NULL, 0 }
	};

CHECK_RETVAL_PTR \
static const BYTE *getContentOID( IN_ENUM( CRYPT_CONTENT ) \
								  const CRYPT_CONTENT_TYPE contentType )
	{
	int i;

	REQUIRES_N( contentType > CRYPT_CONTENT_NONE && \
				contentType < CRYPT_CONTENT_LAST );

	for( i = 0; contentOIDs[ i ].oid != NULL && \
				i < FAILSAFE_ARRAYSIZE( contentOIDs, OID_INFO ); i++ )
		{
		if( contentOIDs[ i ].selectionID == contentType )
			return( contentOIDs[ i ].oid );
		}

	retIntError_Null();
	}

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int copyFromAuxBuffer( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	int bytesCopied, dataLeft;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	/* Copy as much of the signature data as we can across */
	bytesCopied = min( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos,
					   envelopeInfoPtr->auxBufPos );
	REQUIRES( bytesCopied > 0 && \
			  envelopeInfoPtr->bufPos + \
				bytesCopied <= envelopeInfoPtr->bufSize );
	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;
	
	ENSURES( dataLeft >= 0 );

	return( ( dataLeft > 0 ) ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
	}

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeEOCs( INOUT 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;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	REQUIRES( eocLength >= 2 && eocLength <= 16 );	/* Count = 1...8 */

	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 */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeSignedDataHeader( INOUT STREAM *stream,
								  const ENVELOPE_INFO *envelopeInfoPtr,
								  const BOOLEAN isSignedData )
	{
	const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
	ACTION_LIST *actionListPtr;
	long dataSize;
	int hashActionSize = 0, iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	REQUIRES_S( contentOID != NULL );

	/* Determine the size of the hash actions */
	for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
		 actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
		 actionListPtr = actionListPtr->next, iterationCount++ )
		{
		const int actionSize = \
						sizeofContextAlgoID( actionListPtr->iCryptHandle, 
											 CRYPT_ALGO_NONE );
		if( cryptStatusError( actionSize ) )
			return( actionSize );
		hashActionSize += actionSize;
		}
	ENSURES_S( iterationCount < FAILSAFE_ITERATIONS_MED );
	
	/* 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 > 0 ) ? \
			sizeofObject( sizeofObject( envelopeInfoPtr->payloadSize ) ) : 0;
		dataSize = sizeofObject( sizeofOID( contentOID ) + dataSize );

		/* Determine the size of the version, hash algoID, content, 
		   certificate chain, and signatures */
		dataSize = sizeofShortInteger( 1 ) + sizeofObject( hashActionSize ) + \
				   dataSize + envelopeInfoPtr->extraDataSize + \
				   sizeofObject( envelopeInfoPtr->signActionSize );
		}
	ENSURES_S( dataSize == CRYPT_UNUSED || \
			   ( dataSize >= MIN_CRYPT_OBJECTSIZE && \
				 dataSize < MAX_INTLENGTH ) );

	/* Write the SignedData/DigestedData header, version number, and SET OF
	   DigestInfo */
	if( isSignedData )
		{
		status = writeCMSheader( stream, OID_CMS_SIGNEDDATA, 
								 sizeofOID( OID_CMS_SIGNEDDATA ), 
								 dataSize, FALSE );
		}
	else
		{
		status = writeCMSheader( stream, OID_CMS_DIGESTEDDATA, 
								 sizeofOID( OID_CMS_DIGESTEDDATA ), 
								 dataSize, FALSE );
		}
	if( cryptStatusError( status ) )
		return( status );
	writeShortInteger( stream, 1, DEFAULT_TAG );
	writeSet( stream, hashActionSize );
	for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
		 actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
		 actionListPtr = actionListPtr->next, iterationCount++ )
		{
		status = writeContextAlgoID( stream, actionListPtr->iCryptHandle, 
									 CRYPT_ALGO_NONE );
		if( cryptStatusError( status ) )
			return( status );
		}
	ENSURES_S( iterationCount < FAILSAFE_ITERATIONS_MED );

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

/* EncryptedContentInfo contained within EnvelopedData.  This may also be 
   Authenticated or AuthEnc data so the encryption context can be 
   CRYPT_UNUSED */

CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
static int getBlockedPayloadSize( IN_LENGTH_INDEF const long payloadSize, 
								  IN_LENGTH_IV const int blockSize,
								  OUT_LENGTH_INDEF long *blockedPayloadSize )
	{
	long blockedSize;

	assert( isWritePtr( blockedPayloadSize, sizeof( long ) ) );

	REQUIRES( payloadSize == CRYPT_UNUSED || \
			  ( payloadSize > 0 && payloadSize < MAX_INTLENGTH ) );
	REQUIRES( blockSize > 1 && blockSize <= CRYPT_MAX_IVSIZE );

	/* Clear return value */
	*blockedPayloadSize = 0;

	/* If it's an indefinite length payload the blocked size is also of 
	   indefinite length */
	if( payloadSize == CRYPT_UNUSED )
		{
		*blockedPayloadSize = CRYPT_UNUSED;
		return( CRYPT_OK );
		}

	/* Calculate the size of the payload after encryption blocking */
	blockedSize = paddedSize( payloadSize, blockSize );
	*blockedPayloadSize = blockedSize;

	ENSURES( blockedSize >= 8 && \
			 blockedSize <= payloadSize + CRYPT_MAX_IVSIZE );

	return( CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeEncryptedContentHeader( INOUT STREAM *stream,
							IN_BUFFER( contentOIDlength ) const BYTE *contentOID, 
							IN_LENGTH_OID const int contentOIDlength,
							IN_HANDLE const CRYPT_CONTEXT iCryptContext,
							IN_LENGTH_INDEF const long payloadSize, 
							IN_LENGTH_IV const long blockSize )
	{
	long blockedPayloadSize;
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( contentOID, contentOIDlength ) );
	
	REQUIRES( isHandleRangeValid( iCryptContext ) || \
			  iCryptContext == CRYPT_UNUSED );
	REQUIRES( payloadSize == CRYPT_UNUSED || \
			  ( payloadSize > 0 && payloadSize < MAX_INTLENGTH ) );
	REQUIRES( blockSize > 1 && blockSize <= CRYPT_MAX_IVSIZE );

	status = getBlockedPayloadSize( payloadSize, blockSize, 
									&blockedPayloadSize );
	if( cryptStatusError( status ) )
		return( status );
	return( writeCMSencrHeader( stream, contentOID, contentOIDlength,
								blockedPayloadSize, iCryptContext ) );
	}

/* EncryptedData, EnvelopedData */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
static int getEncrypedContentSize( const ENVELOPE_INFO *envelopeInfoPtr,
								   IN_BUFFER( contentOIDlength ) const BYTE *contentOID, 
								   IN_LENGTH_OID const int contentOIDlength,
								   OUT_LENGTH_INDEF long *blockedPayloadSize,
								   OUT_LENGTH_Z long *encrContentInfoSize )

⌨️ 快捷键说明

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