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

📄 deenvel.c

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

#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.h"
#else
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1objs.h"
  #include "keymgmt/asn1oid.h"
  #include "envelope/envelope.h"
#endif /* Compiler-specific includes */

/* Prototypes for functions in asn1objs.c */

int queryObject( STREAM *stream, QUERY_INFO *queryInfo );

/* Prototypes for functions in resource.c */

void initContentListItem( CONTENT_LIST *contentListItem );

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

/* OID information used to read enveloped data */

static const 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 },
	{ NULL, 0, 0, 0 }
	};

static const 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_COMPRESSEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_COMPRESSEDDATA },
	{ 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 queryInfo;
	CONTENT_LIST *contentListItem;
	void *object, *originalObjectPtr = sMemBufPtr( stream );
	int status;

	/* Find the size of the object, allocate a buffer for it, and copy it
	   across */
	status = queryObject( stream, &queryInfo );
	if( cryptStatusError( status ) )
		return( status );
	if( queryInfo.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, queryInfo.size );
		return( ( int ) queryInfo.size );
		}
	if( ( object = malloc( ( size_t ) queryInfo.size ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	sread( stream, object, ( int ) queryInfo.size );

	/* Allocate memory for the new content list item and copy information on
	   the item across */
	contentListItem = createContentListItem( queryInfo.formatType,
											 object, ( int ) queryInfo.size );
	if( contentListItem == NULL )
		{
		if( stream != NULL )
			free( object );
		return( CRYPT_ERROR_MEMORY );
		}
	if( queryInfo.type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
		queryInfo.type == CRYPT_OBJECT_SIGNATURE )
		{
		/* Remember details of the enveloping info we require to continue */
		if( queryInfo.type == CRYPT_OBJECT_PKCENCRYPTED_KEY )
			contentListItem->envInfo = CRYPT_ENVINFO_PRIVATEKEY;
		else
			{
			contentListItem->envInfo = CRYPT_ENVINFO_SIGNATURE;
			contentListItem->hashAlgo = queryInfo.hashAlgo;
			}
		if( queryInfo.formatType == CRYPT_FORMAT_CMS )
			{
			contentListItem->issuerAndSerialNumber = \
						( BYTE * ) contentListItem->object + \
						( ( BYTE * ) queryInfo.iAndSStart - ( BYTE * ) originalObjectPtr );
			contentListItem->issuerAndSerialNumberSize = queryInfo.iAndSLength;
			}
		else
			{
			memcpy( contentListItem->keyID, queryInfo.keyID, 
					queryInfo.keyIDlength );
			contentListItem->keyIDsize = queryInfo.keyIDlength;
			}
		contentListItem->payload = \
						( BYTE * ) contentListItem->object + \
						( ( BYTE * ) queryInfo.dataStart - ( BYTE * ) originalObjectPtr );
		contentListItem->payloadSize = queryInfo.dataLength;
		}
	if( queryInfo.type == CRYPT_OBJECT_ENCRYPTED_KEY )
		{
		/* Remember details of the enveloping info we require to continue */
		if( queryInfo.keySetupAlgo != CRYPT_ALGO_NONE )
			{
			contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
			contentListItem->keySetupIterations = queryInfo.keySetupIterations;
			memcpy( contentListItem->saltOrIV, queryInfo.salt, 
					queryInfo.saltLength );
			contentListItem->saltOrIVsize = queryInfo.saltLength;
			}
		else
			contentListItem->envInfo = CRYPT_ENVINFO_KEY;
		contentListItem->cryptAlgo = queryInfo.cryptAlgo;
		contentListItem->cryptMode = queryInfo.cryptMode;
		contentListItem->payload = \
						( BYTE * ) contentListItem->object + \
						( ( BYTE * ) queryInfo.dataStart - ( BYTE * ) originalObjectPtr );
		contentListItem->payloadSize = queryInfo.dataLength;
		}
	appendContentListItem( envelopeInfoPtr, contentListItem );

	return( ( int ) queryInfo.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;
#ifdef NO_COMPRESSION
				status = CRYPT_ERROR_NOTAVAIL;
#else
				else
					if( inflateInit( &envelopeInfoPtr->zStream ) == Z_OK )
						envelopeInfoPtr->zStreamInited = TRUE;
					else
						status = CRYPT_ERROR_MEMORY;
#endif /* NO_COMPRESSION */
				if( cryptStatusError( status ) )
					{
					sMemDisconnect( &stream );
					return( status );
					}
				state = DEENVSTATE_CONTENT;
				break;

			case ACTION_NONE:
				/* Since we go straight to the data payload there's no nested
				   content type, so we explicitly set it to data */
				envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
				state = DEENVSTATE_DATA;
				break;

			default:
				assert( NOTREACHED );
			}

		/* Remember how far we got */
		streamPos = ( int ) stell( &stream );
		}

	/* Keep consuming information until we run out of input or reach the data
	   payload */
	while( state != DEENVSTATE_DONE )
		{
		/* Check that various values are within range.  They can go out of
		   range if the header is corrupted */
		if( envelopeInfoPtr->hdrSetLength < 0 && \
			envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
			{
			status = CRYPT_ERROR_BADDATA;
			break;
			}

		/* Read the start of the cert set from a keyAgreement's [0] IMPLICIT 
		   SEQUENCE { [0] SET OF Certificate } */
		if( state == DEENVSTATE_SET_ENCR )
			{
			/* Read the SET tag and length */
			status = readSet( &stream, &length );
			if( cryptStatusError( status ) )
				break;

			/* Remember where we are and move on to the next state.  Some
			   implementations use the indefinite-length encoding for this so
			   if there's no length given we have to look for the EOC after
			   each entry read */
			streamPos = ( int ) stell( &stream );
			envelopeInfoPtr->hdrSetLength = ( length ) ? length : CRYPT_UNUSED;
			state = DEENVSTATE_ENCR;
			}

		/* Read and remember a key exchange object from an EncryptionKeyInfo
		   record */
		if( state == DEENVSTATE_ENCR )
			{
			/* Add the object to the content information list */
			status = addContentListItem( &stream, envelopeInfoPtr );
			if( cryptStatusError( status ) )
				break;

			/* Remember where we are and move on to the next state if
			   necessary */
			streamPos = ( int ) stell( &stream );
			if( envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
				{
				envelopeInfoPtr->hdrSetLength -= status;
				if( envelopeInfoPtr->hdrSetLength <= 0 )
					state = DEENVSTATE_ENCRCONTENT;
				}
			else
				if( checkEOC( &stream ) )
					state = DEENVSTATE_ENCRCONTENT;
			}

		/* Read the encrypted content information */
		if( state == DEENVSTATE_ENCRCONTENT )
			{
			QUERY_INFO queryInfo;
			CONTENT_LIST contentListItem;

			/* Read the encrypted content header */
			initContentListItem( &contentListItem );
			contentListItem.envInfo = CRYPT_ENVINFO_SESSIONKEY;
			status = readCMSencrHeader( &stream, nestedContentOIDselection,
										NULL, &queryInfo );
			if( cryptStatusError( status ) )
				break;
			envelopeInfoPtr->contentType = status;
			envelopeInfoPtr->payloadSize = queryInfo.size;
			contentListItem.cryptAlgo = queryInfo.cryptAlgo;
			contentListItem.cryptMode = queryInfo.cryptMode;
			memcpy( contentListItem.saltOrIV, queryInfo.iv, 
					queryInfo.ivLength );
			contentListItem.saltOrIVsize = queryInfo.ivLength;

			/* We've reached encrypted data, we can't go any further until we
			   can either recover the session key from a key exchange object
			   or are fed the session key directly */
			if( envelopeInfoPtr->actionList == NULL )
				{
				CONTENT_LIST *contentListItemPtr;

				/* Remember what we need for later and exit */
				if( ( contentListItemPtr = malloc( sizeof( CONTENT_LIST ) ) ) == NULL )
					{
					status = CRYPT_ERROR_MEMORY;
					break;
					}
				memcpy( contentListItemPtr, &contentListItem,
						sizeof( CONTENT_LIST ) );
				appendContentListItem( envelopeInfoPtr, contentListItemPtr );
				streamPos = ( int ) stell( &stream );
				state = DEENVSTATE_DATA;
				status = CRYPT_ENVELOPE_RESOURCE;
				break;
				}
			assert( envelopeInfoPtr->actionList->action == ACTION_CRYPT );

			/* If the session key was recovered from a key exchange action but
			   we ran out of input data before we could read the
			   encryptedContent info, it'll be present in the action list so
			   we use it to set things up for the decryption.  This can only
			   happen if the caller pushes in just enough data to get past the
			   key exchange actions but not enough to recover the
			   encryptedContent info and then pushes in a key exchange action
			   in response to the CRYPT_ERROR_UNDERFLOW error */
			status = initEnvelopeEncryption( envelopeInfoPtr,
						envelopeInfoPtr->actionList->iCryptHandle, 
						contentListItem.cryptAlgo, contentListItem.cryptMode, 
						contentListItem.saltOrIV, contentListItem.saltOrIVsize, 
						FALSE );
			if( cryptStatusError( status ) )
				break;

			/* Remember where we are and move on to the next state */
			streamPos = ( int ) stell( &stream );
			state = DEENVSTATE_DATA;
			}

		/* Read the start of the SET OF DigestAlgorithmIdentifier */
		if( state == DEENVSTATE_SET_HASH )
			{
			/* Read the SET tag and length */
			status = readSet( &stream, &length );
			if( cryptStatusError( status ) )

⌨️ 快捷键说明

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