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

📄 denv_cms.c

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

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

#ifdef USE_ENVELOPES

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

/* OID information used to read enveloped data */

static const FAR_BSS OID_SELECTION envelopeOIDselection[] = {
	{ OID_CMS_DATA, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
	{ OID_CMS_SIGNEDDATA, 0, 3, ACTION_SIGN },
	{ OID_CMS_ENVELOPEDDATA, 0, 2, ACTION_KEYEXCHANGE },
	{ OID_CMS_DIGESTEDDATA, 0, 2, ACTION_HASH },
	{ OID_CMS_ENCRYPTEDDATA, 0, 2, ACTION_CRYPT },
	{ OID_CMS_COMPRESSEDDATA, 0, 0, ACTION_COMPRESS },
	{ OID_CMS_TSTOKEN, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
	{ OID_MS_SPCINDIRECTDATACONTEXT, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
	{ OID_CRYPTLIB_RTCSREQ, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
	{ OID_CRYPTLIB_RTCSRESP, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
	{ OID_CRYPTLIB_RTCSRESP_EXT, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
	{ NULL, 0, 0, 0 }
	};

static const FAR_BSS OID_SELECTION nestedContentOIDselection[] = {
	{ OID_CMS_DATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_DATA },
	{ OID_CMS_SIGNEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_SIGNEDDATA },
	{ OID_CMS_ENVELOPEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_ENVELOPEDDATA },
	{ OID_CMS_ENCRYPTEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_ENCRYPTEDDATA },
	{ OID_CMS_TSTOKEN, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_TSTINFO },
	{ OID_CMS_COMPRESSEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_COMPRESSEDDATA },
	{ OID_MS_SPCINDIRECTDATACONTEXT, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_SPCINDIRECTDATACONTEXT },
	{ OID_CRYPTLIB_RTCSREQ, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_RTCSREQUEST },
	{ OID_CRYPTLIB_RTCSRESP, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_RTCSRESPONSE },
	{ OID_CRYPTLIB_RTCSRESP_EXT, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_RTCSRESPONSE_EXT },
	{ NULL, 0, 0, 0 }
	};

/* Add information about an object to an envelope's content information list */

static int addContentListItem( STREAM *stream, ENVELOPE_INFO *envelopeInfoPtr,
							   QUERY_INFO *externalQueryInfoPtr )
	{
	QUERY_INFO queryInfo, *queryInfoPtr = ( externalQueryInfoPtr == NULL ) ? \
										  &queryInfo : externalQueryInfoPtr;
	CONTENT_LIST *contentListItem;
	void *object = NULL, *originalObjectPtr = sMemBufPtr( stream );
	int status;

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

	/* Find the size of the object, allocate a buffer for it, and copy it
	   across */
	if( externalQueryInfoPtr == NULL )
		{
		status = queryAsn1Object( stream, queryInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		if( queryInfoPtr->type == CRYPT_OBJECT_NONE )
			{
			/* It's a valid but unrecognised object type (a new 
			   RecipientInfo type which 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 */
			sSkip( stream, queryInfoPtr->size );
			return( ( int ) queryInfoPtr->size );
			}
		if( ( object = clAlloc( "addContentListItem", \
								( size_t ) queryInfoPtr->size ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		sread( stream, object, ( int ) queryInfoPtr->size );
		}

	/* Allocate memory for the new content list item and copy information on
	   the item across */
	contentListItem = createContentListItem( envelopeInfoPtr->memPoolState,
							queryInfoPtr->formatType, object, 
							( int ) queryInfoPtr->size,
							queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE );
	if( contentListItem == NULL )
		{
		if( externalQueryInfoPtr == NULL )
			clFree( "addContentListItem", object );
		return( CRYPT_ERROR_MEMORY );
		}
	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;
		memcpy( encrInfo->saltOrIV, queryInfoPtr->iv, queryInfoPtr->ivLength );
		encrInfo->saltOrIVsize = queryInfoPtr->ivLength;
		}
	if( queryInfoPtr->type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
		queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE )
		{
		/* Remember details of the enveloping info 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 )
			{
			contentListItem->issuerAndSerialNumber = \
					( BYTE * ) contentListItem->object + \
					( ( BYTE * ) queryInfoPtr->iAndSStart - \
					  ( BYTE * ) originalObjectPtr );
			contentListItem->issuerAndSerialNumberSize = queryInfoPtr->iAndSLength;
			}
		else
			{
			memcpy( contentListItem->keyID, queryInfoPtr->keyID, 
					queryInfoPtr->keyIDlength );
			contentListItem->keyIDsize = queryInfoPtr->keyIDlength;
			}
		contentListItem->payload = \
					( BYTE * ) contentListItem->object + \
					( ( BYTE * ) queryInfoPtr->dataStart - \
					  ( BYTE * ) originalObjectPtr );
		contentListItem->payloadSize = queryInfoPtr->dataLength;
		if( queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE && \
			queryInfoPtr->formatType == CRYPT_FORMAT_CMS && \
			queryInfoPtr->unauthAttributeStart != NULL )
			{
			CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;

			sigInfo->extraData2 = \
					( BYTE * ) contentListItem->object + \
					( ( BYTE * ) queryInfoPtr->unauthAttributeStart - \
					  ( BYTE * ) originalObjectPtr );
			sigInfo->extraData2Length = queryInfoPtr->unauthAttributeLength;
			}
		}
	if( queryInfoPtr->type == CRYPT_OBJECT_ENCRYPTED_KEY )
		{
		CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;

		/* Remember details of the enveloping info we require to continue */
		if( queryInfoPtr->keySetupAlgo != CRYPT_ALGO_NONE )
			{
			contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
			encrInfo->keySetupAlgo = queryInfoPtr->keySetupAlgo;
			encrInfo->keySetupIterations = queryInfoPtr->keySetupIterations;
			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;
		contentListItem->payload = \
						( BYTE * ) contentListItem->object + \
						( ( BYTE * ) queryInfoPtr->dataStart - ( BYTE * ) originalObjectPtr );
		contentListItem->payloadSize = queryInfoPtr->dataLength;
		}
	appendContentListItem( envelopeInfoPtr, contentListItem );

	return( ( int ) queryInfoPtr->size );
	}

/****************************************************************************
*																			*
*						Process Envelope Preamble/Postamble					*
*																			*
****************************************************************************/

/* Process the non-data portions of an envelope.  This is a complex event-
   driven state machine, but instead of reading along a (hypothetical
   Turing-machine) tape, someone has taken the tape and cut it into bits and
   keeps feeding them to us and saying "See what you can do with this" (and
   occasionally "Where's the bloody spoons?").  The following code implements
   this state machine.

	Encr. with key exchange: SET_ENCR -> ENCR -> ENCRCONTENT -> DATA
	Encr. with key agreement: "
	Encr.: ENCRCONTENT -> DATA
	Signed: SET_HASH -> HASH -> CONTENT -> DATA */

static int processPreamble( ENVELOPE_INFO *envelopeInfoPtr )
	{
	DEENV_STATE state = envelopeInfoPtr->deenvState;
	STREAM stream;
	int length, streamPos = 0, status = CRYPT_OK;

	sMemConnect( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufPos );

	/* If we haven't started doing anything yet, try and read the outer
	   header fields */
	if( state == DEENVSTATE_NONE )
		{
		BYTE algoIDbuffer[ MAX_OID_SIZE ];
		int algoIDlength;

		/* Read the outer CMS header */
		status = readCMSheader( &stream, envelopeOIDselection,
								&envelopeInfoPtr->payloadSize, FALSE );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( status );
			}

		/* Determine the next state to continue processing */
		switch( status )
			{
			case ACTION_KEYEXCHANGE:
				envelopeInfoPtr->usage = ACTION_CRYPT;
				if( peekTag( &stream ) != 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 ) )
						{
						sMemDisconnect( &stream );
						return( status );
						}
					}
				state = DEENVSTATE_SET_ENCR;
				break;

			case ACTION_CRYPT:
				envelopeInfoPtr->usage = ACTION_CRYPT;
				state = DEENVSTATE_ENCRCONTENT;
				break;

			case ACTION_SIGN:
				envelopeInfoPtr->usage = ACTION_SIGN;
				state = DEENVSTATE_SET_HASH;
				break;

			case ACTION_COMPRESS:
				/* With compressed data all we need to do is check that the
				   fixed AlgorithmIdentifier is present and set up the 
				   decompression stream, after which we go straight to the 
				   content */
				envelopeInfoPtr->usage = ACTION_COMPRESS;
				status = readRawObject( &stream, algoIDbuffer, &algoIDlength, 
										MAX_OID_SIZE, BER_SEQUENCE );
				if( !cryptStatusError( status ) && \
					( algoIDlength != sizeofOID( ALGOID_CMS_ZLIB ) || \
					  memcmp( algoIDbuffer, ALGOID_CMS_ZLIB, algoIDlength ) ) )
					status = CRYPT_ERROR_BADDATA;
				else
#ifdef USE_COMPRESSION
					if( inflateInit( &envelopeInfoPtr->zStream ) == Z_OK )

⌨️ 快捷键说明

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