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

📄 cms_denv.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int processEOCTrailer( INOUT STREAM *stream, 
							  IN_ENUM_OPT( ACTION ) const ACTION_TYPE usage )
	{
	const int noEOCs = ( usage == ACTION_NONE ) ? 2 : \
					   ( usage == ACTION_SIGN || \
						 usage == ACTION_MAC ) ? 3 : \
					   ( usage == ACTION_COMPRESS ) ? 5 : 4;
	int i;

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

	REQUIRES( usage >= ACTION_NONE && usage < ACTION_LAST );

	/* Consume any EOCs up to the maximum amount possible.  In theory we 
	   could be rather liberal with trailing EOCs since it's not really 
	   necessary for the caller to push in every last one, however if we
	   assume that seeing at least one EOC is enough to signal the end of
	   all content this can lead to problems if adding the EOCs occurs
	   over a pushData boundary.  What can happen here is that the code will 
	   see the start of the string of EOCs on the first push, record the 
	   end-of-data-reached state, and then report a CRYPT_ERROR_COMPLETE 
	   when the remainder of the string of EOCs are pushed the next time
	   round.  To avoid this problem we have to be pedantic and require
	   that callers push all EOCs */
	for( i = 0; i < noEOCs; i++ )
		{
		const int value = checkEOC( stream );
		if( cryptStatusError( value ) )
			return( value );
		if( value == FALSE )
			return( CRYPT_ERROR_BADDATA );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						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.: ENCRCONTENT -> DATA
	Signed: SET_HASH -> HASH -> CONTENT -> DATA
	MACd: SET_ENCR -> ENCR -> HASH -> CONTENT -> DATA */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int processPreamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	DEENV_STATE state = envelopeInfoPtr->deenvState;
	STREAM stream;
	int remainder, streamPos = 0, iterationCount = 0, status = CRYPT_OK;

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

	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 )
		{
		status = processEnvelopeHeader( envelopeInfoPtr, &stream, &state );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			retExt( status,
					( status, ENVELOPE_ERRINFO,
					  "Invalid CMS envelope header" ) );
			}

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

	/* Keep consuming information until we either run out of input or reach 
	   the data payload.  Although in theory we should really use 
	   FAILSAFE_ITERATIONS_MED for this loop, in practice we have to use
	   FAILSAFE_ITERATIONS_LARGE because it's possible to generate S/MIME 
	   messages with large numbers of recipients for mailing lists.  This 
	   would never occur in any normal usage, but we have to allow for it for
	   mailing-list use */
	while( state != DEENVSTATE_DONE && \
		   iterationCount++ < FAILSAFE_ITERATIONS_LARGE )
		{
		/* Read the start of the SET OF RecipientInfo/SET OF 
		   DigestAlgorithmIdentifier */
		if( state == DEENVSTATE_SET_ENCR )
			{
			long setLongLength;

			/* Read the SET tag and length.  We have to read the length as
			   a long value in order to handle cases where there's a large 
			   amount of key management data involving a great many 
			   recipients */
			status = readLongSet( &stream, &setLongLength );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid SET OF RecipientInfo header", 35 );
				break;
				}
			envelopeInfoPtr->hdrSetLength = setLongLength;

			/* 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 (setLength == CRYPT_UNUSED) we 
			   have to look for the EOC after each entry read */
			streamPos = stell( &stream );
			state = DEENVSTATE_ENCR;
			}
		if( state == DEENVSTATE_SET_HASH )
			{
			int setLength;

			/* Read the SET tag and length */
			status = readSetI( &stream, &setLength );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid SET OF DigestAlgorithmIdentifier "
								"header", 47 );
				break;
				}
			envelopeInfoPtr->hdrSetLength = setLength;

			/* 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 (setLength == CRYPT_UNUSED) we 
			   have to look for the EOC after each entry read */
			streamPos = stell( &stream );
			state = DEENVSTATE_HASH;
			}

		/* Read and remember a key exchange object from an EncryptionKeyInfo
		   record */
		if( state == DEENVSTATE_ENCR )
			{
			int contentItemLength;

			/* Add the object to the content information list */
			status = addContentListItem( envelopeInfoPtr, &stream, NULL, 
										 &contentItemLength );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid EncryptionKeyInfo key exchange "
								"record", 45 );
				break;
				}

			/* Remember where we are and move on to the next state if
			   necessary */
			streamPos = stell( &stream );
			if( envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
				{
				if( contentItemLength > envelopeInfoPtr->hdrSetLength )
					{
					status = CRYPT_ERROR_BADDATA;
					break;
					}
				envelopeInfoPtr->hdrSetLength -= contentItemLength;
				if( envelopeInfoPtr->hdrSetLength <= 0 )
					{
					state = ( envelopeInfoPtr->usage == ACTION_MAC ) ? \
							DEENVSTATE_HASH : DEENVSTATE_ENCRCONTENT;
					}
				}
			else
				{
				const int value = checkEOC( &stream );
				if( cryptStatusError( value ) )
					{
					status = value;
					break;
					}
				if( value == TRUE )
					{
					state = ( envelopeInfoPtr->usage == ACTION_MAC ) ? \
							DEENVSTATE_HASH : DEENVSTATE_ENCRCONTENT;
					}
				}
			}

		/* Read the encrypted content information */
		if( state == DEENVSTATE_ENCRCONTENT )
			{
			status = processEncryptionHeader( envelopeInfoPtr, &stream );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid encrypted content header", 32 );
				break;
				}

			/* Remember where we are and move on to the next state */
			streamPos = stell( &stream );
			state = DEENVSTATE_DATA;
			if( envelopeInfoPtr->actionList == NULL )
				{
				/* If we haven't got a session key to decrypt the data that
				   follows we can't go beyond this point */
				status = CRYPT_ENVELOPE_RESOURCE;
				break;
				}
			}

		/* Read and remember a MAC object from a MACAlgorithmIdentifier
		   record */
		if( state == DEENVSTATE_HASH && \
			envelopeInfoPtr->usage == ACTION_MAC )
			{
			status = processHashHeader( envelopeInfoPtr, &stream );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid hashed/MACd content header", 34 );
				break;
				}

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

		/* Read and remember a hash object from a DigestAlgorithmIdentifier
		   record */
		if( state == DEENVSTATE_HASH )
			{
			status = processHashHeader( envelopeInfoPtr, &stream );
			if( cryptStatusError( status ) )
				break;

			/* Remember where we are and move on to the next state if
			   necessary */
			if( envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
				{
				const int hashInfoLength = stell( &stream ) - streamPos;
				if( hashInfoLength < 0 || \
					hashInfoLength > envelopeInfoPtr->hdrSetLength )
					{
					status = CRYPT_ERROR_BADDATA;
					break;
					}
				envelopeInfoPtr->hdrSetLength -= hashInfoLength;
				streamPos = stell( &stream );
				if( envelopeInfoPtr->hdrSetLength <= 0 )
					state = DEENVSTATE_CONTENT;
				}
			else
				{
				const int value = checkEOC( &stream );
				if( cryptStatusError( value ) )
					{
					status = value;
					break;
					}
				if( value == TRUE )
					state = DEENVSTATE_CONTENT;
				}
			}

		/* Read the encapsulated content header */
		if( state == DEENVSTATE_CONTENT )
			{
			int contentType;

			status = contentType = \
				readCMSheader( &stream, nestedContentOIDinfo,
							   FAILSAFE_ARRAYSIZE( nestedContentOIDinfo, OID_INFO ),
							   &envelopeInfoPtr->payloadSize, TRUE );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid encapsulated content header", 35 );
				break;
				}
			envelopeInfoPtr->contentType = contentType;

			/* If there's no content included and it's not an attributes-only
			   message then this is a detached signature with the content 
			   supplied anderswhere */
			if( envelopeInfoPtr->payloadSize == 0 && \
				!( envelopeInfoPtr->flags & ENVELOPE_ATTRONLY ) )
				envelopeInfoPtr->flags |= ENVELOPE_DETACHED_SIG;

			/* Remember where we are and move on to the next state */
			streamPos = stell( &stream );
			state = ( envelopeInfoPtr->payloadSize == 0 && \
					  ( envelopeInfoPtr->flags & ( ENVELOPE_DETACHED_SIG | \
												   ENVELOPE_ATTRONLY ) ) ) ? \
					DEENVSTATE_DONE : DEENVSTATE_DATA;

			/* If this is MACd data and we haven't loaded a key to MAC the 
			   data that follows we can't go beyond this point */
			if( envelopeInfoPtr->usage == ACTION_MAC )
				{
				if( envelopeInfoPtr->actionList == NULL )
					{
					status = CRYPT_ENVELOPE_RESOURCE;
					break;
					}
				REQUIRES( envelopeInfoPtr->actionList->action == ACTION_MAC );
				status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
										  IMESSAGE_CHECK, NULL, 
										  MESSAGE_CHECK_MAC );
				if( cryptStatusError( status ) )
					{
					status = CRYPT_ENVELOPE_RESOURCE;
					break;
					}
				}
			}

		/* Start the decryption process if necessary */
		if( state == DEENVSTATE_DATA )
			{
			/* Synchronise the data stream processing to the start of the
			   encrypted data and move back to the start of the data
			   stream */
			status = envelopeInfoPtr->syncDeenvelopeData( envelopeInfoPtr,
														  &stream );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 

⌨️ 快捷键说明

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