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

📄 deenvel.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
				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_HASH;
			}

		/* Read and remember a hash object from a DigestAlgorithmIdentifier
		   record */
		if( state == DEENVSTATE_HASH )
			{
			CRYPT_ALGO hashAlgo;
			CRYPT_CONTEXT iHashContext;
			ACTION_LIST *actionListPtr;

			/* Create the hash object from the data */
			status = readContextAlgoID( &stream, &iHashContext, NULL, 
										DEFAULT_TAG );
			if( cryptStatusOK( status ) )
				status = krnlSendMessage( iHashContext, 
										  RESOURCE_IMESSAGE_GETATTRIBUTE,
										  &hashAlgo, CRYPT_CTXINFO_ALGO );
			if( cryptStatusError( status ) )
				break;

			/* Check whether an identical hash action is already present,
			   either through being supplied externally or from a duplicate
			   entry in the set */
			for( actionListPtr = envelopeInfoPtr->actionList; 
				 actionListPtr != NULL; actionListPtr = actionListPtr->next )
				{
				CRYPT_ALGO actionHashAlgo;

				status = krnlSendMessage( actionListPtr->iCryptHandle, 
										  RESOURCE_IMESSAGE_GETATTRIBUTE,
										  &actionHashAlgo, CRYPT_CTXINFO_ALGO );
				if( cryptStatusOK( status ) && actionHashAlgo == hashAlgo )
					{
					/* There's a duplicate action present, destroy the one
					   we've just created and exit */
					krnlSendNotifier( iHashContext, 
									  RESOURCE_IMESSAGE_DECREFCOUNT );
					break;
					}
				}
			if( actionListPtr == NULL )
				{
				/* We didn't find any duplicates, append the new hash action 
				   to the action list and remember that hashing is now 
				   active */
				if( addAction( &envelopeInfoPtr->actionList, ACTION_HASH, 
							   iHashContext ) == NULL )
					{
					status = CRYPT_ERROR_MEMORY;
					break;
					}
				envelopeInfoPtr->hashActionsActive = TRUE;
				}
			assert( envelopeInfoPtr->actionList->action == ACTION_HASH );

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

		/* Read the encapsulated content header */
		if( state == DEENVSTATE_CONTENT )
			{
			status = readCMSheader( &stream, nestedContentOIDselection,
									&envelopeInfoPtr->payloadSize, TRUE );
			if( cryptStatusError( status ) )
				break;
			envelopeInfoPtr->contentType = status;
			status = CRYPT_OK;

			/* If there's no content included, this is a detached signature
			   with the content supplied anderswhere */
			if( !envelopeInfoPtr->payloadSize )
				envelopeInfoPtr->flags |= ENVELOPE_DETACHED_SIG;

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

		/* 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 ) )
				break;
			streamPos = 0;

			/* We're done */
			state = DEENVSTATE_DONE;
			assert( actionsOK( envelopeInfoPtr ) );
			}
		}
	envelopeInfoPtr->deenvState = state;

	/* Consume the input we've processed so far by moving everything past the
	   current position down to the start of the memory buffer */
	length = envelopeInfoPtr->bufPos - streamPos;
	if( length > 0 && streamPos )
		memmove( envelopeInfoPtr->buffer, envelopeInfoPtr->buffer + streamPos,
				 length );
	envelopeInfoPtr->bufPos = length;

	/* If all went OK but we're still not out of the header information,
	   return an underflow error */
	if( cryptStatusOK( status ) && state != DEENVSTATE_DONE )
		status = CRYPT_ERROR_UNDERFLOW;

	/* Clean up */
	sMemDisconnect( &stream );
	return( status );
	}

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

	/* If that's all there is, return.  This check isn't necessary for the 
	   following code to work, but is required to avoid triggering the stream
	   check for a zero-length stream open */
	if( state == DEENVSTATE_NONE && envelopeInfoPtr->usage != ACTION_SIGN && \
		envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		{
		/* Definite-length data with no trailer, nothing left to process */
		envelopeInfoPtr->deenvState = DEENVSTATE_DONE;
		return( CRYPT_OK );
		}

	/* If there's not enough data left in the stream to do anything with,
	   return immediately.  Again, this isn't necessary but is required to
	   avoid triggering the zero-length stream check */
	if( envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft < 2 )
		return( CRYPT_ERROR_UNDERFLOW );

	/* Start reading the trailer data from the end of the payload */
	sMemConnect( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
				 envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft );

	/* If we haven't started doing anything yet, figure out what we should be
	   looking for */
	if( state == DEENVSTATE_NONE )
		if( envelopeInfoPtr->usage == ACTION_SIGN )
			{
			DEENV_STATE newState;

			/* Read the SignedData EOC's if necessary */
			if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
				{
				if( ( sgetc( &stream ) || sgetc( &stream ) || \
					  sgetc( &stream ) || sgetc( &stream ) ) )
					{
					status = ( sGetStatus( &stream ) == CRYPT_OK ) ? \
							 CRYPT_ERROR_BADDATA : sGetStatus( &stream );
					sMemDisconnect( &stream );
					return( status );
					}
				}
			else
				{
				/* If the data was encoded using a mixture of definite and
				   indefinite encoding there may be EOC's present even though
				   the length is known, so we skip them if necessary */
				checkEOC( &stream );
				checkEOC( &stream );
				}

			/* Check whether there's a cert chain to follow */
			status = peekTag( &stream );
			if( cryptStatusError( status ) )
				return( status );
			newState = ( status == MAKE_CTAG( 0 ) ) ? \
					   DEENVSTATE_CERTSET : DEENVSTATE_SET_SIG;

			/* If we've seen all the signed data, complete the hashing.  When
			   we reach this point there may still be unhashed data left in 
			   the buffer (it won't have been hashed yet because the hashing 
			   is performed when the data is copied out, after unwrapping and 
			   deblocking and whatnot) so we hash it before we wrap up the 
			   hashing */
			if( !( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
				{
				if( envelopeInfoPtr->dataLeft )
					status = 
						envelopeInfoPtr->processExtraData( envelopeInfoPtr,
												envelopeInfoPtr->buffer, 
												envelopeInfoPtr->dataLeft );
				if( !cryptStatusError( status ) )	/* Status == tag */
					status = \
						envelopeInfoPtr->processExtraData( envelopeInfoPtr, 
														   "", 0 );
				if( cryptStatusError( status ) )
					{
					sMemDisconnect( &stream );
					return( status );
					}
				}

			/* Move on to the next state */
			streamPos = ( int ) stell( &stream );
			state = newState;
			}
		else
			/* Just look for EOC's */
			state = DEENVSTATE_EOC;

	/* Keep consuming information until we run out of input or read the end
	   of the data */
	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 cert chain */
		if( state == DEENVSTATE_CERTSET )
			{
			int length;

			/* Read the cert chain into the aux.buffer.  We can't import it
			   at this point because we need the SignerInfo to definitively 
			   identify the leaf cert.  Usually there's only one leaf, but
			   there will be more than one if there are multiple signatures
			   present, or if the sending app decides to shovel in assorted
			   (non-relevant) certs */
			length = getObjectLength( sMemBufPtr( &stream ), 
									  sMemDataLeft( &stream ) );
			if( cryptStatusError( length ) )
				{
				status = length;
				break;
				}
			if( envelopeInfoPtr->auxBuffer == NULL )
				{
				/* Allocate a buffer for the cert chain if necessary.  This
				   may already be allocated if the previous attempt to read
				   the chain failed due to there being insufficient data in
				   the envelope buffer */
				if( ( envelopeInfoPtr->auxBuffer = malloc( length ) ) == NULL )
					{
					status = CRYPT_ERROR_MEMORY;
					break;
					}
				envelopeInfoPtr->auxBufSize = length;
				}
			assert( envelopeInfoPtr->auxBufSize == length );
			status = sread( &stream, envelopeInfoPtr->auxBuffer, 
							envelopeInfoPtr->auxBufSize );
			if( cryptStatusError( status ) )
				break;
			
			/* Remember where we are and move on to the next state */
			streamPos = ( int ) stell( &stream );
			state = DEENVSTATE_SET_SIG;
			}

		/* Read the start of the SET OF Signature */
		if( state == DEENVSTATE_SET_SIG )
			{
			/* 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_SIG;
			}

		/* Read and remember a signature object from a Signature record */
		if( state == DEENVSTATE_SIG )
			{
			/* 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 = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
							DEENVSTATE_EOC : DEENVSTATE_DONE;
				}
			else
				if( checkEOC( &stream ) )
					state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
							DEENVSTATE_EOC : DEENVSTATE_DONE;
			}

		/* Handle end-of-contents octets */
		if( state == DEENVSTATE_EOC )
			{
			BYTE buffer[ 16 ];
			const int eocLen = ( envelopeInfoPtr->usage == ACTION_SIGN ) ? \
							   6 : 8;

			status = sread( &stream, buffer, eocLen );
			if( cryptStatusOK( status ) && \
				memcmp( buffer, "\x00\x00\x00\x00\x00\x00\x00\x00", eocLen ) )
				status = CRYPT_ERROR_BADDATA;
			if( cryptStatusError( status ) )
				break;

			/* We're done */
			streamPos = ( int ) stell( &stream );
			state = DEENVSTATE_DONE;
			break;
			}
		}
	envelopeInfoPtr->deenvState = state;
	sMemDisconnect( &stream );

	/* Consume the input we've processed so far by moving everything past the
	   current position down to the start of the memory buffer */
	length = envelopeInfoPtr->bufPos - ( envelopeInfoPtr->dataLeft + streamPos );
	if( length > 0 && streamPos > 0 )
		memmove( envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
				 envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft + streamPos,
				 length );
	envelopeInfoPtr->bufPos = envelopeInfoPtr->dataLeft + length;

	/* Adjust the error state based on what's left in the envelope buffer.
	   If there's data still present, we don't report certain types of errors
	   because they don't affect the data, only the trailer */
	if( envelopeInfoPtr->dataLeft )
		{
		/* If we've got an underflow error but there's payload data left to
		   be copied out, convert the status to OK since the caller can still
		   continue before they need to copy in more data.  Since there's
		   more data left to process, we return OK_SPECIAL to tell the
		   calling function not to perform any cleanup */
		if( status == CRYPT_ERROR_UNDERFLOW )
			status = OK_SPECIAL;
		}
	else
		/* If all went OK but we're still not out of the header information,
		   return an underflow error */
		if( cryptStatusOK( status ) && state != DEENVSTATE_DONE )
			status = CRYPT_ERROR_UNDERFLOW;

	return( cryptStatusError( status ) ? status : CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Envelope Access Routines						*
*																			*
****************************************************************************/

void initCMSDeenveloping( ENVELOPE_INFO *envelopeInfoPtr )
	{
	/* Set the access method pointers */
	envelopeInfoPtr->processPreamble = processPreamble;
	envelopeInfoPtr->processPostamble = processPostamble;

	/* Set up the processing state information */
	envelopeInfoPtr->deenvState = DEENVSTATE_NONE;
	}

⌨️ 快捷键说明

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