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

📄 cms_denv.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					  cryptlib De-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 */

#ifdef USE_ENVELOPES

/****************************************************************************
*																			*
*								Utility Routines							*
*																			*
****************************************************************************/

/* OID information used to read enveloped data */

static const CMS_CONTENT_INFO FAR_BSS oidInfoSignedData = { 0, 3 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoEnvelopedData = { 0, 2 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoDigestedData = { 0, 2 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoEncryptedData = { 0, 2 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoCompressedData = { 0, 0 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoAuthData = { 0, 0 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoAuthEnvData = { 0, 0 };

static const OID_INFO FAR_BSS envelopeOIDinfo[] = {
	{ OID_CMS_DATA, ACTION_NONE },
	{ OID_CMS_SIGNEDDATA, ACTION_SIGN, &oidInfoSignedData },
	{ OID_CMS_ENVELOPEDDATA, ACTION_KEYEXCHANGE, &oidInfoEnvelopedData },
	{ OID_CMS_DIGESTEDDATA, ACTION_HASH, &oidInfoDigestedData },
	{ OID_CMS_ENCRYPTEDDATA, ACTION_CRYPT, &oidInfoEncryptedData },
	{ OID_CMS_COMPRESSEDDATA, ACTION_COMPRESS, &oidInfoCompressedData },
	{ OID_CMS_AUTHDATA, ACTION_MAC, &oidInfoAuthData },
	{ OID_CMS_AUTHENVDATA, ACTION_MAC, &oidInfoAuthEnvData },
	{ OID_CMS_TSTOKEN, ACTION_NONE },
	{ OID_MS_SPCINDIRECTDATACONTEXT, ACTION_NONE },
	{ OID_CRYPTLIB_RTCSREQ, ACTION_NONE },
	{ OID_CRYPTLIB_RTCSRESP, ACTION_NONE },
	{ OID_CRYPTLIB_RTCSRESP_EXT, ACTION_NONE },
	{ NULL, 0 }, { NULL, 0 }
	};

static const OID_INFO FAR_BSS nestedContentOIDinfo[] = {
	{ OID_CMS_DATA, CRYPT_CONTENT_DATA },
	{ OID_CMS_SIGNEDDATA, CRYPT_CONTENT_SIGNEDDATA },
	{ OID_CMS_ENVELOPEDDATA, CRYPT_CONTENT_ENVELOPEDDATA },
	{ 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 },
	{ NULL, 0 }, { NULL, 0 }
	};

/* 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->deenvState < DEENVSTATE_NONE || \
		envelopeInfoPtr->deenvState >= DEENVSTATE_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 );

	return( TRUE );
	}

/* Add information about an object to an envelope's content information list.  
   The content information can be supplied in one of two ways, either 
   implicitly via the data in the stream or explicitly via a QUERY_INFO
   structure */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
static int addContentListItem( INOUT ENVELOPE_INFO *envelopeInfoPtr,
							   INOUT_OPT STREAM *stream, 
							   OUT_OPT QUERY_INFO *externalQueryInfoPtr,
							   OUT_LENGTH_SHORT_Z int *itemSize )
	{
	QUERY_INFO queryInfo, *queryInfoPtr = ( externalQueryInfoPtr == NULL ) ? \
										  &queryInfo : externalQueryInfoPtr;
	CONTENT_LIST *contentListItem;
	BYTE *contentListObjectPtr = NULL;
	int objectSize = 0, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( ( stream == NULL && \
			  isWritePtr( externalQueryInfoPtr, sizeof( QUERY_INFO ) ) ) || \
			( isWritePtr( stream, sizeof( STREAM ) ) && \
			  externalQueryInfoPtr == NULL ) );
	assert( isWritePtr( itemSize, sizeof( int ) ) );

	REQUIRES( ( stream == NULL && externalQueryInfoPtr != NULL ) || \
			  ( stream != NULL && externalQueryInfoPtr == NULL ) );

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

	/* Make sure that there's room to add another list item */
	if( !moreContentItemsPossible( envelopeInfoPtr->contentList ) )
		return( CRYPT_ERROR_OVERFLOW );

	/* Find the size of the object, allocate a buffer for it, and copy it
	   across */
	if( externalQueryInfoPtr == NULL )
		{
		/* See what we've got.  This call verifies that all of the object 
		   data is present in the stream so in theory we don't have to check 
		   the following reads, but we check them anyway just to be sure */
		status = queryAsn1Object( stream, queryInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		objectSize = ( int ) queryInfoPtr->size;

		/* If it's a valid but unrecognised object type (a new RecipientInfo 
		   type that was added after this version of cryptlib was released), 
		   skip it and continue (if there are no recognised RecipientInfo 
		   types, the code will automatically fall back to asking the user 
		   for a raw session key).  Alternatively, we could just add it to 
		   the content list as an unrecognised object type, but this would 
		   lead to confusion for the caller when non-object-types appear 
		   when they query the current component */
		if( queryInfoPtr->type == CRYPT_OBJECT_NONE )
			{
			status = sSkip( stream, objectSize );
			if( cryptStatusError( status ) )
				return( status );
			*itemSize = objectSize;

			return( CRYPT_OK );
			}

		/* Read the object data into memory */
		if( ( contentListObjectPtr = clAlloc( "addContentListItem", \
											  objectSize ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		status = sread( stream, contentListObjectPtr, objectSize );
		if( cryptStatusError( status ) )
			{
			clFree( "addContentListItem", contentListObjectPtr );
			return( status );
			}
		}
	ENSURES( ( externalQueryInfoPtr != NULL ) || \
			 ( queryInfoPtr->size > 0 && \
			   queryInfoPtr->size < MAX_INTLENGTH ) );
			 /* If the query info is supplied externally it's a template that
			    doesn't correspond to any actual data */

	/* Allocate memory for the new content list item and copy information on
	   the item across */
	status = createContentListItem( &contentListItem, 
					envelopeInfoPtr->memPoolState, queryInfoPtr->formatType, 
					contentListObjectPtr, objectSize,
					( queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE ) ? \
						TRUE : FALSE );
	if( cryptStatusError( status ) )
		{
		if( contentListObjectPtr == NULL )
			clFree( "addContentListItem", contentListObjectPtr );
		return( status );
		}
	if( externalQueryInfoPtr != NULL )
		{
		CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;

		/* It's externally-supplied crypto algorithm details from an
		   encrypted data header */
		contentListItem->envInfo = CRYPT_ENVINFO_SESSIONKEY;
		encrInfo->cryptAlgo = queryInfoPtr->cryptAlgo;
		encrInfo->cryptMode = queryInfoPtr->cryptMode;
		if( queryInfoPtr->ivLength > 0 )
			{
			REQUIRES( queryInfoPtr->ivLength > 0 && \
					  queryInfoPtr->ivLength <= CRYPT_MAX_IVSIZE );
			memcpy( encrInfo->saltOrIV, queryInfoPtr->iv, 
					queryInfoPtr->ivLength );
			encrInfo->saltOrIVsize = queryInfoPtr->ivLength;
			}
		}
	if( queryInfoPtr->type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
		queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE )
		{
		/* Remember the details of the enveloping info that we require to 
		   continue */
		if( queryInfoPtr->type == CRYPT_OBJECT_PKCENCRYPTED_KEY )
			contentListItem->envInfo = CRYPT_ENVINFO_PRIVATEKEY;
		else
			{
			contentListItem->envInfo = CRYPT_ENVINFO_SIGNATURE;
			contentListItem->clSigInfo.hashAlgo = queryInfoPtr->hashAlgo;
			}
		if( queryInfoPtr->formatType == CRYPT_FORMAT_CMS )
			{
			REQUIRES( rangeCheck( queryInfoPtr->iAndSStart, 
								  queryInfoPtr->iAndSLength, objectSize ) );
			contentListItem->issuerAndSerialNumber = contentListObjectPtr + \
													 queryInfoPtr->iAndSStart;
			contentListItem->issuerAndSerialNumberSize = queryInfoPtr->iAndSLength;
			}
		else
			{
			REQUIRES( queryInfoPtr->keyIDlength > 0 && \
					  queryInfoPtr->keyIDlength <= CRYPT_MAX_HASHSIZE );
			memcpy( contentListItem->keyID, queryInfoPtr->keyID,
					queryInfoPtr->keyIDlength );
			contentListItem->keyIDsize = queryInfoPtr->keyIDlength;
			}
		REQUIRES( rangeCheck( queryInfoPtr->dataStart, 
							  queryInfoPtr->dataLength, objectSize ) );
		contentListItem->payload = contentListObjectPtr + \
								   queryInfoPtr->dataStart;
		contentListItem->payloadSize = queryInfoPtr->dataLength;
		if( queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE && \
			queryInfoPtr->formatType == CRYPT_FORMAT_CMS && \
			queryInfoPtr->unauthAttributeStart > 0 )
			{
			CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;

			REQUIRES( rangeCheck( queryInfoPtr->unauthAttributeStart,
								  queryInfoPtr->unauthAttributeLength, 
								  objectSize ) );
			sigInfo->extraData2 = contentListObjectPtr + \
								  queryInfoPtr->unauthAttributeStart;
			sigInfo->extraData2Length = queryInfoPtr->unauthAttributeLength;
			}
		}
	if( queryInfoPtr->type == CRYPT_OBJECT_ENCRYPTED_KEY )
		{
		CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;

		/* Remember the details of the enveloping info that we require to 
		   continue */
		if( queryInfoPtr->keySetupAlgo != CRYPT_ALGO_NONE )
			{
			contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
			encrInfo->keySetupAlgo = queryInfoPtr->keySetupAlgo;
			encrInfo->keySetupIterations = queryInfoPtr->keySetupIterations;
			if( queryInfoPtr->saltLength > 0 )
				{
				REQUIRES( queryInfoPtr->saltLength > 0 && \
						  queryInfoPtr->saltLength <= CRYPT_MAX_HASHSIZE );
				memcpy( encrInfo->saltOrIV, queryInfoPtr->salt,
						queryInfoPtr->saltLength );
				encrInfo->saltOrIVsize = queryInfoPtr->saltLength;
				}
			}
		else
			contentListItem->envInfo = CRYPT_ENVINFO_KEY;
		encrInfo->cryptAlgo = queryInfoPtr->cryptAlgo;
		encrInfo->cryptMode = queryInfoPtr->cryptMode;
		REQUIRES( rangeCheck( queryInfoPtr->dataStart, 
							  queryInfoPtr->dataLength, objectSize ) );
		contentListItem->payload = contentListObjectPtr + \
								   queryInfoPtr->dataStart;
		contentListItem->payloadSize = queryInfoPtr->dataLength;
		}
	appendContentListItem( envelopeInfoPtr, contentListItem );
	*itemSize = ( int ) queryInfoPtr->size;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Header Processing Routines						*
*																			*
****************************************************************************/

/* Process the outer CMS envelope header */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int processEnvelopeHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr, 
								  INOUT STREAM *stream, 
								  OUT_ENUM_OPT( DEENV_STATE ) DEENV_STATE *state )
	{
	int status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( state, sizeof( DEENV_STATE ) ) );

	/* Clear return value */
	*state = DEENVSTATE_NONE;

	/* Read the outer CMS header */
	status = readCMSheader( stream, envelopeOIDinfo,
							FAILSAFE_ARRAYSIZE( envelopeOIDinfo, OID_INFO ),
							&envelopeInfoPtr->payloadSize, FALSE );
	if( cryptStatusError( status ) )
		return( status );

	/* Determine the next state to continue processing */
	switch( status )
		{
		case ACTION_KEYEXCHANGE:
#ifdef USE_KEA
			status = peekTag( stream );
			if( cryptStatusError( status ) )
				return( status );
			if( status != BER_SET )
				{
				/* There may be key agreement data present, try and read the 
				   start of the [0] IMPLICIT SEQUENCE { [0] SET OF Certificate } */
				readConstructed( stream, NULL, 0 );
				status = readConstructed( stream, NULL, 0 );
				if( cryptStatusError( status ) )
					return( status );
				}
#endif /* USE_KEA */

⌨️ 快捷键说明

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