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

📄 decode.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					  cryptlib Datagram Decoding Routines					*
*						Copyright Peter Gutmann 1996-2008					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "envelope.h"
  #include "asn1.h"
  #include "misc_rw.h"
  #include "pgp_rw.h"
#else
  #include "envelope/envelope.h"
  #include "misc/asn1.h"
  #include "misc/misc_rw.h"
  #include "misc/pgp_rw.h"
#endif /* Compiler-specific includes */

/*			 .... NO! ...				   ... MNO! ...
		   ..... MNO!! ...................... MNNOO! ...
		 ..... MMNO! ......................... MNNOO!! .
		.... MNOONNOO!	 MMMMMMMMMMPPPOII!	 MNNO!!!! .
		 ... !O! NNO! MMMMMMMMMMMMMPPPOOOII!! NO! ....
			...... ! MMMMMMMMMMMMMPPPPOOOOIII! ! ...
		   ........ MMMMMMMMMMMMPPPPPOOOOOOII!! .....
		   ........ MMMMMOOOOOOPPPPPPPPOOOOMII! ...
			....... MMMMM..	   OPPMMP	 .,OMI! ....
			 ...... MMMM::	 o.,OPMP,.o	  ::I!! ...
				 .... NNM:::.,,OOPM!P,.::::!! ....
				  .. MMNNNNNOOOOPMO!!IIPPO!!O! .....
				 ... MMMMMNNNNOO:!!:!!IPPPPOO! ....
				   .. MMMMMNNOOMMNNIIIPPPOO!! ......
				  ...... MMMONNMMNNNIIIOO!..........
			   ....... MN MOMMMNNNIIIIIO! OO ..........
			......... MNO! IiiiiiiiiiiiI OOOO ...........
		  ...... NNN.MNO! . O!!!!!!!!!O . OONO NO! ........
		   .... MNNNNNO! ...OOOOOOOOOOO .  MMNNON!........
		   ...... MNNNNO! .. PPPPPPPPP .. MMNON!........
			  ...... OO! ................. ON! .......
				 ................................

   Be very careful when modifying this code, the data manipulation that it
   performs is somewhat tricky */

#ifdef USE_ENVELOPES

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

/* 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 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 );

	/* Make sure that the block buffer position is within bounds */
	if( envelopeInfoPtr->blockSize > 0 && \
		( envelopeInfoPtr->blockBufferPos < 0 || \
		  envelopeInfoPtr->blockBufferPos >= envelopeInfoPtr->blockSize || \
		  envelopeInfoPtr->blockSize > CRYPT_MAX_IVSIZE ) )
		return( FALSE );

	/* Make sure that the out-of-band data buffer is within bounds */
	if( envelopeInfoPtr->oobBufPos < 0 || \
		envelopeInfoPtr->oobBufPos > OOB_BUFFER_SIZE )
		return( FALSE );

	/* Make sure that the envelope internal bookeeping is OK */
	if( envelopeInfoPtr->segmentSize < 0 || \
		envelopeInfoPtr->segmentSize >= MAX_INTLENGTH || \
		envelopeInfoPtr->dataLeft < 0 || \
		envelopeInfoPtr->dataLeft >= MAX_INTLENGTH )
		return( FALSE );

	return( TRUE );
	}

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

/* Handle the end-of-data and PKCS #5 block padding if necessary:

			   pad
	+-------+-------+-------+
	|		|		|		|
	+-------+-------+-------+
			^		^
			|		|
		 padPtr	  bPos */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int processDataEnd( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If we're using a block cipher, undo the PKCS #5 padding which is
	   present at the end of the block */
	if( envelopeInfoPtr->blockSize > 1 )
		{
		int padSize, i;

		REQUIRES( envelopeInfoPtr->bufPos > 0 );

		/* Make sure that the padding size is valid */
		padSize = envelopeInfoPtr->buffer[ envelopeInfoPtr->bufPos - 1 ];
		if( padSize < 1 || padSize > envelopeInfoPtr->blockSize || \
			padSize > envelopeInfoPtr->bufPos )
			return( CRYPT_ERROR_BADDATA );

		/* Check the padding data */
		envelopeInfoPtr->bufPos -= padSize;
		for( i = 0; i < padSize - 1; i++ )
			{
			if( envelopeInfoPtr->buffer[ envelopeInfoPtr->bufPos + i ] != padSize )
				return( CRYPT_ERROR_BADDATA );
			}
		ENSURES( envelopeInfoPtr->bufPos >= 0 && \
				 envelopeInfoPtr->bufPos < MAX_INTLENGTH );
		}

	/* Remember that we've reached the end of the payload and where the
	   payload ends ("This was the end of the river all right") */
	envelopeInfoPtr->dataFlags |= ENVDATA_ENDOFCONTENTS;
	envelopeInfoPtr->dataLeft = envelopeInfoPtr->bufPos;

	ENSURES( sanityCheck( envelopeInfoPtr ) );
	return( CRYPT_OK );
	}

/* Process a sub-segment */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int processSegment( INOUT ENVELOPE_INFO *envelopeInfoPtr, 
						   INOUT STREAM *stream, 
						   OUT_LENGTH_Z long *segmentLength )
	{
	int status;

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

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

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

	/* Check for the EOCs that mark the end of the overall data */
	status = checkEOC( stream );
	if( cryptStatusError( status ) )
		return( status );
	if( status == TRUE )
		{
		/* We've seen the EOC, wrap up the processing */
		return( processDataEnd( envelopeInfoPtr ) );
		}

	/* It's a new sub-segment, get its length */
	status = readLongGenericHole( stream, segmentLength, BER_OCTETSTRING );
	if( cryptStatusError( status ) )
		return( status );
	if( *segmentLength == CRYPT_UNUSED )
		{
		/* An indefinite-length encoding within a constructed data item 
		   isn't allowed */
		return( CRYPT_ERROR_BADDATA );
		}

	return( CRYPT_OK );
	}

#ifdef USE_PGP

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int processPgpSegment( INOUT ENVELOPE_INFO *envelopeInfoPtr, 
							  INOUT STREAM *stream, 
							  OUT_LENGTH_Z long *segmentLength )
	{
	int status;

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

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

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

	/* Get the next sub-segment's length */
	status = pgpReadPartialLength( stream, segmentLength );
	if( cryptStatusError( status ) )
		{
		/* If we get an OK_SPECIAL returned it's just an indication that 
		   we've got another partial length (with other segments to follow) 
		   and not an actual error */
		if( status == OK_SPECIAL )
			return( CRYPT_OK );

		/* Alongside normal errors this may also be an OK_SPECIAL to 
		   indicate that we got another partial length (with other segments 
		   to follow), which the caller will handle as a non-error */
		return( status );
		}

	/* We've read a length that doesn't use the indefinite-length encoding 
	   so it's the last data segment, shift from indefinite to definite-
	   length mode */
#if 0	/* 2/04/08 It's not really a NOSEGMENT it's just a short definite-
				   length segment */
	envelopeInfoPtr->dataFlags |= ENVDATA_NOSEGMENT;
#endif /* 0 */
	if( *segmentLength <= 0 )
		{
		/* It's a terminating zero-length segment, wrap up the processing.
		   Unlike CMS, PGP can add other odds and ends at this point so we
		   don't exit yet but fall through to the code that follows */
		status = processDataEnd( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If this is a packet with an MDC packet tacked on, adjust the data 
	   length for the length of the MDC packet */
	if( envelopeInfoPtr->dataFlags & ENVDATA_HASATTACHEDOOB )
		{
		/* If the MDC data is larger than the length of the last segment, 
		   adjust its effefctive size to zero.  This is rather problematic 
		   in that if the sender chooses to break the MDC packet across the 
		   partial-header boundary it'll include some of the MDC data with 
		   the payload, but there's no easy solution to this, the problem 
		   lies in the PGP spec for allowing a length encoding form that 
		   makes one-pass processing impossible.  Hopefully implementations 
		   will realise this and never break the MDC data over a partial-
		   length header */
		*segmentLength -= PGP_MDC_PACKET_SIZE;
		if( *segmentLength < 0 )
			{
			assert( DEBUG_WARN );

			*segmentLength = 0;
			}
		}

	/* Convert the last segment into a definite-length segment.  When we 
	   return from this the calling code will immediately call 
	   getNextSegment() again since we've consumed some input, at which 
	   point the definite-length payload size will be set and the call will 
	   return with OK_SPECIAL to tell the caller that there's no more length 
	   information to fetch */
	envelopeInfoPtr->payloadSize = *segmentLength;
	*segmentLength = 0;

	ENSURES( sanityCheck( envelopeInfoPtr ) );

	return( CRYPT_OK );
	}
#endif /* USE_PGP */

/* Decode the header for the next segment in the buffer.  Returns the number
   of bytes consumed or zero if more data is required to decode the header */

typedef enum {
	SEGMENT_NONE,			/* No segment status */
	SEGMENT_FIXEDLENGTH,	/* Single fixed-length segment, no more segments 
							   to process */
	SEGMENT_INSUFFICIENTDATA,/* Need more data to continue */
	SEGMENT_ENDOFDATA,		/* No more data to process */
	SEGMENT_LAST			/* Last possible segment status */
	} SEGMENT_STATUS;

CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
static int getNextSegment( INOUT ENVELOPE_INFO *envelopeInfoPtr, 
						   IN_BUFFER( length ) const BYTE *buffer, 
						   IN_LENGTH const int length, 
						   OUT_LENGTH_SHORT_Z int *bytesConsumed,
						   OUT_ENUM_OPT( SEGMENT ) SEGMENT_STATUS *segmentStatus )
	{
	STREAM stream;
	long segmentLength;
	int status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( isReadPtr( buffer, length ) );
	assert( isWritePtr( bytesConsumed, sizeof( int ) ) );
	assert( isWritePtr( segmentStatus, sizeof( SEGMENT_STATUS ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );
	REQUIRES( length > 0 && length < MAX_INTLENGTH );

	/* Clear return values */
	*bytesConsumed = 0;
	*segmentStatus = SEGMENT_NONE;

	/* If we've already processed the entire payload, don't do anything.
	   This can happen when we're using the definite encoding form, since
	   the EOC flag is set elsewhere as soon as the entire payload has been
	   copied to the buffer */
	if( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS )
		{
		REQUIRES( envelopeInfoPtr->segmentSize <= 0 );

		*segmentStatus = SEGMENT_ENDOFDATA;
		return( OK_SPECIAL );
		}

	/* If we're using the definite encoding form there's a single segment 
	   equal in length to the entire payload */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		{
		envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;
		*segmentStatus = SEGMENT_FIXEDLENGTH;
		return( OK_SPECIAL );
		}

	/* If we're using the indefinite form but it's an envelope type that

⌨️ 快捷键说明

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